Merge from Chromium at DEPS revision r213057

This commit was generated by merge_to_master.py.

Change-Id: I3e2e2506eb9b0080157e9c5f133559df3e600388
diff --git a/chrome/browser/DEPS b/chrome/browser/DEPS
index 8a76397..278632f 100644
--- a/chrome/browser/DEPS
+++ b/chrome/browser/DEPS
@@ -74,10 +74,10 @@
   "+libxml",  # For search engine definition parsing.
   "+third_party/apple_sample_code",  # Apple code ImageAndTextCell.
   "+third_party/bzip2",
-  "+third_party/cld",
   "+third_party/expat",
   "+third_party/iaccessible2",
-  "+third_party/icu",
+  "+third_party/icu/source/common/unicode",
+  "+third_party/icu/source/i18n/unicode",
   "+third_party/isimpledom",
   "+third_party/leveldatabase",
   "+third_party/libevent",  # For the remote V8 debugging server
@@ -91,17 +91,13 @@
   # 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",
@@ -111,7 +107,5 @@
   "+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/WebView.h",
 ]
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index cfafecc..fe000fc 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -21,6 +21,7 @@
 #include "chrome/common/chrome_switches.h"
 #include "components/nacl/common/nacl_switches.h"
 #include "content/public/browser/user_metrics.h"
+#include "extensions/common/switches.h"
 #include "grit/chromium_strings.h"
 #include "grit/generated_resources.h"
 #include "grit/google_chrome_strings.h"
@@ -439,13 +440,6 @@
 #endif
   },
   {
-    "enable-d3d11",
-    IDS_FLAGS_ENABLE_D3D11_NAME,
-    IDS_FLAGS_ENABLE_D3D11_DESCRIPTION,
-    kOsWin,
-    SINGLE_VALUE_TYPE(switches::kEnableD3D11)
-  },
-  {
     "disable-webrtc",
     IDS_FLAGS_DISABLE_WEBRTC_NAME,
     IDS_FLAGS_DISABLE_WEBRTC_DESCRIPTION,
@@ -552,7 +546,7 @@
     IDS_FLAGS_EXTENSIONS_ON_CHROME_URLS_NAME,
     IDS_FLAGS_EXTENSIONS_ON_CHROME_URLS_DESCRIPTION,
     kOsAll,
-    SINGLE_VALUE_TYPE(switches::kExtensionsOnChromeURLs)
+    SINGLE_VALUE_TYPE(extensions::switches::kExtensionsOnChromeURLs)
   },
   {
     "enable-fast-unload",
@@ -583,14 +577,6 @@
     SINGLE_VALUE_TYPE(switches::kEnableAppWindowControls)
   },
   {
-    "action-box",
-    IDS_FLAGS_ACTION_BOX_NAME,
-    IDS_FLAGS_ACTION_BOX_DESCRIPTION,
-    kOsDesktop,
-    ENABLE_DISABLE_VALUE_TYPE_AND_VALUE(switches::kActionBox, "1",
-                                        switches::kActionBox, "0")
-  },
-  {
     "script-badges",
     IDS_FLAGS_SCRIPT_BADGES_NAME,
     IDS_FLAGS_SCRIPT_BADGES_DESCRIPTION,
@@ -997,6 +983,13 @@
     kOsCrOS,
     SINGLE_VALUE_TYPE(chromeos::switches::kNoDiscardTabs)
   },
+  {
+    "ash-enable-docked-windows",
+    IDS_FLAGS_DOCKED_WINDOWS_NAME,
+    IDS_FLAGS_DOCKED_WINDOWS_DESCRIPTION,
+    kOsCrOS,
+    SINGLE_VALUE_TYPE(ash::switches::kAshEnableDockedWindows)
+  },
 #endif
   {
     "enable-download-resumption",
@@ -1116,6 +1109,13 @@
     SINGLE_VALUE_TYPE(chromeos::switches::kFileManagerEnableSharing)
   },
   {
+    "file-manager-enable-folder-shortcuts",
+    IDS_FLAGS_FILE_MANAGER_ENABLE_FOLDER_SHORTCUTS,
+    IDS_FLAGS_FILE_MANAGER_ENABLE_FOLDER_SHORTCUTS_DESCRIPTION,
+    kOsCrOS,
+    SINGLE_VALUE_TYPE(chromeos::switches::kFileManagerEnableFolderShortcuts)
+  },
+  {
     "disable-quickoffice-component-app",
     IDS_FLAGS_DISABLE_QUICKOFFICE_COMPONENT_APP_NAME,
     IDS_FLAGS_DISABLE_QUICKOFFICE_COMPONENT_APP_DESCRIPTION,
@@ -1227,7 +1227,7 @@
     IDS_FLAGS_ASH_AUDIO_DEVICE_MENU_NAME,
     IDS_FLAGS_ASH_AUDIO_DEVICE_MENU_DESCRIPTION,
     kOsCrOS,
-    SINGLE_VALUE_TYPE(ash::switches::kAshEnableAudioDeviceMenu)
+    ENABLE_DISABLE_VALUE_TYPE("", ash::switches::kAshDisableAudioDeviceMenu)
   },
   {
     "enable-carrier-switching",
@@ -1259,12 +1259,13 @@
     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,
+    "password-autofill-public-suffix-domain-matching",
+    IDS_FLAGS_PASSWORD_AUTOFILL_PUBLIC_SUFFIX_DOMAIN_MATCHING_NAME,
+    IDS_FLAGS_PASSWORD_AUTOFILL_PUBLIC_SUFFIX_DOMAIN_MATCHING_DESCRIPTION,
     kOsAndroid,
-    SINGLE_VALUE_TYPE(
-        switches::kEnablePasswordAutofillPublicSuffixDomainMatching)
+    ENABLE_DISABLE_VALUE_TYPE(
+        switches::kEnablePasswordAutofillPublicSuffixDomainMatching,
+        switches::kDisablePasswordAutofillPublicSuffixDomainMatching)
   },
   {
     "enable-deferred-image-decoding",
diff --git a/chrome/browser/accessibility/accessibility_extension_apitest.cc b/chrome/browser/accessibility/accessibility_extension_apitest.cc
index 29e54c4..b66e2f3 100644
--- a/chrome/browser/accessibility/accessibility_extension_apitest.cc
+++ b/chrome/browser/accessibility/accessibility_extension_apitest.cc
@@ -10,6 +10,9 @@
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/common/chrome_switches.h"
 
+#if defined(OS_WIN) && defined(USE_ASH)
+#include "base/win/windows_version.h"
+#endif
 
 // Times out on win asan, http://crbug.com/166026
 #if defined(OS_WIN) && defined(ADDRESS_SANITIZER)
@@ -18,6 +21,12 @@
 #define MAYBE_GetAlertsForTab GetAlertsForTab
 #endif
 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, MAYBE_GetAlertsForTab) {
+#if defined(OS_WIN) && defined(USE_ASH)
+  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
+  if (base::win::GetVersion() >= base::win::VERSION_WIN8)
+    return;
+#endif
+
   content::WebContents* web_contents =
       browser()->tab_strip_model()->GetActiveWebContents();
   ASSERT_TRUE(web_contents);
diff --git a/chrome/browser/android/chrome_jni_registrar.cc b/chrome/browser/android/chrome_jni_registrar.cc
index 79bbecf..cf5c8dc 100644
--- a/chrome/browser/android/chrome_jni_registrar.cc
+++ b/chrome/browser/android/chrome_jni_registrar.cc
@@ -11,6 +11,7 @@
 #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/field_trial_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"
@@ -66,6 +67,7 @@
   { "ContentViewUtil", RegisterContentViewUtil },
   { "DevToolsServer", RegisterDevToolsServer },
   { "FaviconHelper", FaviconHelper::RegisterFaviconHelper },
+  { "FieldTrialHelper", RegisterFieldTrialHelper },
   { "IntentHelper", RegisterIntentHelper },
   { "JavascriptAppModalDialog",
     JavascriptAppModalDialogAndroid::RegisterJavascriptAppModalDialog },
diff --git a/chrome/browser/android/field_trial_helper.cc b/chrome/browser/android/field_trial_helper.cc
new file mode 100644
index 0000000..b3be6d2
--- /dev/null
+++ b/chrome/browser/android/field_trial_helper.cc
@@ -0,0 +1,33 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/android/field_trial_helper.h"
+
+#include <jni.h>
+
+#include "base/android/jni_string.h"
+#include "base/metrics/field_trial.h"
+#include "jni/FieldTrialHelper_jni.h"
+
+using base::android::ConvertJavaStringToUTF8;
+using base::android::ConvertUTF8ToJavaString;
+
+static jstring GetFieldTrialFullName(JNIEnv* env,
+                                     jclass clazz,
+                                     jstring jtrial_name) {
+  std::string trial_name(ConvertJavaStringToUTF8(env, jtrial_name));
+  return ConvertUTF8ToJavaString(
+      env,
+      base::FieldTrialList::FindFullName(trial_name)).Release();
+}
+
+namespace chrome {
+namespace android {
+
+bool RegisterFieldTrialHelper(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+}  // namespace android
+}  // namespace chrome
diff --git a/chrome/browser/android/field_trial_helper.h b/chrome/browser/android/field_trial_helper.h
new file mode 100644
index 0000000..6f92ac0
--- /dev/null
+++ b/chrome/browser/android/field_trial_helper.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_FIELD_TRIAL_HELPER_H_
+#define CHROME_BROWSER_ANDROID_FIELD_TRIAL_HELPER_H_
+
+#include <jni.h>
+
+namespace chrome {
+namespace android {
+
+bool RegisterFieldTrialHelper(JNIEnv* env);
+
+}  // namespace android
+}  // namespace chrome
+
+#endif  // CHROME_BROWSER_ANDROID_FIELD_TRIAL_HELPER_H_
diff --git a/chrome/browser/android/most_visited_sites.cc b/chrome/browser/android/most_visited_sites.cc
index 779fb55..79ca5c8 100644
--- a/chrome/browser/android/most_visited_sites.cc
+++ b/chrome/browser/android/most_visited_sites.cc
@@ -148,6 +148,8 @@
     return;
 
   TopSites* top_sites = profile->GetTopSites();
+  if (!top_sites)
+    return;
 
   scoped_refptr<NativeCallback> native_callback =
       new NativeCallback(j_callback_obj, static_cast<int>(num_results));
@@ -181,3 +183,18 @@
           url_string,
           top_sites, base::Owned(j_callback_ref)));
 }
+
+void BlacklistUrl(JNIEnv* env, jclass clazz, jobject j_profile, jstring j_url) {
+  Profile* profile = ProfileAndroid::FromProfileAndroid(j_profile);
+
+  DCHECK(profile);
+  if (!profile)
+    return;
+
+  TopSites* top_sites = profile->GetTopSites();
+  if (!top_sites)
+    return;
+
+  std::string url_string = ConvertJavaStringToUTF8(env, j_url);
+  top_sites->AddBlacklistedURL(GURL(url_string));
+}
diff --git a/chrome/browser/app_controller_mac.h b/chrome/browser/app_controller_mac.h
index 46d8a05..4ea1356 100644
--- a/chrome/browser/app_controller_mac.h
+++ b/chrome/browser/app_controller_mac.h
@@ -81,6 +81,9 @@
 
   scoped_ptr<PrefChangeRegistrar> profilePrefRegistrar_;
   PrefChangeRegistrar localPrefRegistrar_;
+
+  // The main menu item showing the name of a currently focused packaged app.
+  base::scoped_nsobject<NSMenuItem> appMenuItem_;
 }
 
 @property(readonly, nonatomic) BOOL startupComplete;
diff --git a/chrome/browser/app_controller_mac.mm b/chrome/browser/app_controller_mac.mm
index 22e3d58..7e6222b 100644
--- a/chrome/browser/app_controller_mac.mm
+++ b/chrome/browser/app_controller_mac.mm
@@ -4,6 +4,7 @@
 
 #import "chrome/browser/app_controller_mac.h"
 
+#include "apps/shell_window.h"
 #include "base/auto_reset.h"
 #include "base/bind.h"
 #include "base/command_line.h"
@@ -26,6 +27,7 @@
 #include "chrome/browser/download/download_service_factory.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/first_run/first_run.h"
 #include "chrome/browser/lifetime/application_lifetime.h"
 #include "chrome/browser/printing/print_dialog_cloud.h"
@@ -69,6 +71,7 @@
 #include "chrome/common/chrome_paths_internal.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/cloud_print/cloud_print_class_mac.h"
+#include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_constants.h"
 #include "chrome/common/mac/app_mode_common.h"
 #include "chrome/common/pref_names.h"
@@ -193,6 +196,7 @@
 - (BOOL)shouldQuitWithInProgressDownloads;
 - (void)executeApplication:(id)sender;
 - (void)profileWasRemoved:(const base::FilePath&)profilePath;
+- (void)showOrHideMenuItemsForPackagedApp:(NSNotification*)notification;
 @end
 
 class AppControllerProfileObserver : public ProfileInfoCacheObserver {
@@ -308,6 +312,12 @@
   // Set up the command updater for when there are no windows open
   [self initMenuState];
 
+  [[NSNotificationCenter defaultCenter]
+      addObserver:self
+         selector:@selector(showOrHideMenuItemsForPackagedApp:)
+             name:NSWindowDidBecomeMainNotification
+           object:nil];
+
   // Initialize the Profile menu.
   [self initProfileMenu];
 }
@@ -1378,6 +1388,52 @@
       WorkAreaChanged());
 }
 
+// If the window is an app window, show the menu bar for that app, otherwise
+// restore the Chrome menu bar.
+- (void)showOrHideMenuItemsForPackagedApp:(NSNotification*)notification {
+  NSMenu* mainMenu = [NSApp mainMenu];
+  apps::ShellWindow* shellWindow =
+      extensions::ShellWindowRegistry::GetShellWindowForNativeWindowAnyProfile(
+          [notification object]);
+
+  if (!shellWindow) {
+    if (!appMenuItem_)
+      return;
+
+    [mainMenu removeItem:appMenuItem_];
+    appMenuItem_.reset();
+
+    // Restore the Chrome main menu bar.
+    for (NSMenuItem* item in [mainMenu itemArray])
+      [item setHidden:NO];
+
+    return;
+  }
+
+  const extensions::Extension* app = shellWindow->extension();
+  NSString* appId = base::SysUTF8ToNSString(app->id());
+  NSString* title = base::SysUTF8ToNSString(app->name());
+
+  if (appMenuItem_) {
+    if ([[appMenuItem_ title] isEqualToString:appId])
+      return;
+
+    [mainMenu removeItem:appMenuItem_];
+  } else {
+    // Hide everything and add a menu item for the app.
+    for (NSMenuItem* item in [mainMenu itemArray])
+      [item setHidden:YES];
+  }
+
+  appMenuItem_.reset(
+      [[NSMenuItem alloc] initWithTitle:appId
+                                 action:nil
+                          keyEquivalent:@""]);
+  base::scoped_nsobject<NSMenu> appMenu([[NSMenu alloc] initWithTitle:title]);
+  [appMenuItem_ setSubmenu:appMenu];
+  [mainMenu addItem:appMenuItem_];
+}
+
 @end  // @implementation AppController
 
 //---------------------------------------------------------------------------
diff --git a/chrome/browser/app_controller_mac_browsertest.mm b/chrome/browser/app_controller_mac_browsertest.mm
index 11f2c98..567d183 100644
--- a/chrome/browser/app_controller_mac_browsertest.mm
+++ b/chrome/browser/app_controller_mac_browsertest.mm
@@ -6,10 +6,15 @@
 
 #include "base/command_line.h"
 #include "base/mac/scoped_nsobject.h"
+#include "base/strings/sys_string_conversions.h"
 #include "chrome/app/chrome_command_ids.h"
 #import "chrome/browser/app_controller_mac.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/browser.h"
 #include "chrome/browser/ui/browser_list.h"
+#include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/host_desktop.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #import "chrome/common/chrome_switches.h"
@@ -19,7 +24,8 @@
 
 namespace {
 
-class AppControllerPlatformAppBrowserTest : public InProcessBrowserTest {
+class AppControllerPlatformAppBrowserTest
+    : public extensions::PlatformAppBrowserTest {
  protected:
   AppControllerPlatformAppBrowserTest()
       : active_browser_list_(BrowserList::GetInstance(
@@ -27,6 +33,7 @@
   }
 
   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
+    PlatformAppBrowserTest::SetUpCommandLine(command_line);
     command_line->AppendSwitchASCII(switches::kAppId,
                                     "1234");
   }
@@ -48,6 +55,72 @@
   EXPECT_EQ(1u, active_browser_list_->size());
 }
 
+// Test that focusing an app window changes the menu bar.
+IN_PROC_BROWSER_TEST_F(AppControllerPlatformAppBrowserTest,
+                       PlatformAppFocusUpdatesMenuBar) {
+  base::scoped_nsobject<AppController> app_controller(
+      [[AppController alloc] init]);
+
+  // Start two apps and wait for them to be launched.
+  ExtensionTestMessageListener listener_1("Launched", false);
+  const extensions::Extension* app_1 =
+      InstallAndLaunchPlatformApp("minimal_id");
+  ASSERT_TRUE(listener_1.WaitUntilSatisfied());
+  ExtensionTestMessageListener listener_2("Launched", false);
+  const extensions::Extension* app_2 =
+      InstallAndLaunchPlatformApp("minimal");
+  ASSERT_TRUE(listener_2.WaitUntilSatisfied());
+
+  NSMenu* main_menu = [NSApp mainMenu];
+  NSUInteger initial_menu_item_count = [[main_menu itemArray] count];
+
+  // When an app is focused, all Chrome menu items should be hidden, and a menu
+  // item for the app should be added.
+  apps::ShellWindow* app_1_shell_window =
+      extensions::ShellWindowRegistry::Get(profile())->
+          GetShellWindowsForApp(app_1->id()).front();
+  [[NSNotificationCenter defaultCenter]
+      postNotificationName:NSWindowDidBecomeMainNotification
+                    object:app_1_shell_window->GetNativeWindow()];
+  NSArray* item_array = [main_menu itemArray];
+  EXPECT_EQ(initial_menu_item_count + 1, [item_array count]);
+  for (NSUInteger i = 0; i < initial_menu_item_count; ++i)
+    EXPECT_TRUE([[item_array objectAtIndex:i] isHidden]);
+  NSMenuItem* last_item = [item_array lastObject];
+  EXPECT_EQ(app_1->id(), base::SysNSStringToUTF8([last_item title]));
+  EXPECT_EQ(app_1->name(),
+            base::SysNSStringToUTF8([[last_item submenu] title]));
+  EXPECT_FALSE([last_item isHidden]);
+
+  // When another app is focused, the menu item for the app should change.
+  apps::ShellWindow* app_2_shell_window =
+      extensions::ShellWindowRegistry::Get(profile())->
+          GetShellWindowsForApp(app_2->id()).front();
+  [[NSNotificationCenter defaultCenter]
+      postNotificationName:NSWindowDidBecomeMainNotification
+                    object:app_2_shell_window->GetNativeWindow()];
+  item_array = [main_menu itemArray];
+  EXPECT_EQ(initial_menu_item_count + 1, [item_array count]);
+  for (NSUInteger i = 0; i < initial_menu_item_count; ++i)
+    EXPECT_TRUE([[item_array objectAtIndex:i] isHidden]);
+  last_item = [item_array lastObject];
+  EXPECT_EQ(app_2->id(), base::SysNSStringToUTF8([last_item title]));
+  EXPECT_EQ(app_2->name(),
+            base::SysNSStringToUTF8([[last_item submenu] title]));
+  EXPECT_FALSE([last_item isHidden]);
+
+  // When Chrome is focused, the menu item for the app should be removed.
+  NSWindow* browser_native_window =
+      active_browser_list_->get(0)->window()->GetNativeWindow();
+  [[NSNotificationCenter defaultCenter]
+      postNotificationName:NSWindowDidBecomeMainNotification
+                    object:browser_native_window];
+  item_array = [main_menu itemArray];
+  EXPECT_EQ(initial_menu_item_count, [item_array count]);
+  for (NSUInteger i = 0; i < initial_menu_item_count; ++i)
+    EXPECT_FALSE([[item_array objectAtIndex:i] isHidden]);
+}
+
 class AppControllerWebAppBrowserTest : public InProcessBrowserTest {
  protected:
   AppControllerWebAppBrowserTest()
diff --git a/chrome/browser/autocomplete/autocomplete_browsertest.cc b/chrome/browser/autocomplete/autocomplete_browsertest.cc
index 8161ce37..1f43df5 100644
--- a/chrome/browser/autocomplete/autocomplete_browsertest.cc
+++ b/chrome/browser/autocomplete/autocomplete_browsertest.cc
@@ -32,6 +32,10 @@
 #include "content/public/browser/notification_types.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+#if defined(OS_WIN) && defined(USE_ASH)
+#include "base/win/windows_version.h"
+#endif
+
 namespace {
 
 string16 AutocompleteResultAsString(const AutocompleteResult& result) {
@@ -65,6 +69,12 @@
 };
 
 IN_PROC_BROWSER_TEST_F(AutocompleteBrowserTest, Basic) {
+#if defined(OS_WIN) && defined(USE_ASH)
+  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
+  if (base::win::GetVersion() >= base::win::VERSION_WIN8)
+    return;
+#endif
+
   WaitForTemplateURLServiceToLoad();
   LocationBar* location_bar = GetLocationBar();
   OmniboxView* location_entry = location_bar->GetLocationEntry();
@@ -109,6 +119,12 @@
 #endif
 
 IN_PROC_BROWSER_TEST_F(AutocompleteBrowserTest, MAYBE_Autocomplete) {
+#if defined(OS_WIN) && defined(USE_ASH)
+  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
+  if (base::win::GetVersion() >= base::win::VERSION_WIN8)
+    return;
+#endif
+
   WaitForTemplateURLServiceToLoad();
   // The results depend on the history backend being loaded. Make sure it is
   // loaded so that the autocomplete results are consistent.
@@ -153,9 +169,15 @@
 }
 
 IN_PROC_BROWSER_TEST_F(AutocompleteBrowserTest, TabAwayRevertSelect) {
+#if defined(OS_WIN) && defined(USE_ASH)
+  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
+  if (base::win::GetVersion() >= base::win::VERSION_WIN8)
+    return;
+#endif
+
   WaitForTemplateURLServiceToLoad();
   // http://code.google.com/p/chromium/issues/detail?id=38385
-  // Make sure that tabbing away from an empty omnibar causes a revert
+  // Make sure that tabbing away from an empty omnibox causes a revert
   // and select all.
   LocationBar* location_bar = GetLocationBar();
   OmniboxView* location_entry = location_bar->GetLocationEntry();
@@ -174,6 +196,12 @@
 }
 
 IN_PROC_BROWSER_TEST_F(AutocompleteBrowserTest, FocusSearch) {
+#if defined(OS_WIN) && defined(USE_ASH)
+  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
+  if (base::win::GetVersion() >= base::win::VERSION_WIN8)
+    return;
+#endif
+
   WaitForTemplateURLServiceToLoad();
   LocationBar* location_bar = GetLocationBar();
   OmniboxView* location_entry = location_bar->GetLocationEntry();
diff --git a/chrome/browser/autocomplete/autocomplete_controller.cc b/chrome/browser/autocomplete/autocomplete_controller.cc
index 39937f9..77f53f8 100644
--- a/chrome/browser/autocomplete/autocomplete_controller.cc
+++ b/chrome/browser/autocomplete/autocomplete_controller.cc
@@ -151,12 +151,6 @@
   bool use_hqp = !!(provider_types & AutocompleteProvider::TYPE_HISTORY_QUICK);
   // TODO(mrossetti): Permanently modify the HistoryURLProvider to not search
   // titles once HQP is turned on permanently.
-  // History quick provider can be used on all platforms other than Android.
-  // TODO(jcivelli): Enable the History Quick Provider and figure out why it
-  // reports the wrong results for some pages.
-#if defined(OS_ANDROID)
-  use_hqp = false;
-#endif
 
   if (provider_types & AutocompleteProvider::TYPE_BUILTIN)
     providers_.push_back(new BuiltinProvider(this, profile));
diff --git a/chrome/browser/autocomplete/autocomplete_match.cc b/chrome/browser/autocomplete/autocomplete_match.cc
index fc6774c..9c542ac 100644
--- a/chrome/browser/autocomplete/autocomplete_match.cc
+++ b/chrome/browser/autocomplete/autocomplete_match.cc
@@ -43,7 +43,6 @@
       relevance(0),
       typed_count(-1),
       deletable(false),
-      inline_autocomplete_offset(string16::npos),
       transition(content::PAGE_TRANSITION_GENERATED),
       is_history_what_you_typed_match(false),
       type(AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED),
@@ -59,7 +58,6 @@
       relevance(relevance),
       typed_count(-1),
       deletable(deletable),
-      inline_autocomplete_offset(string16::npos),
       transition(content::PAGE_TRANSITION_TYPED),
       is_history_what_you_typed_match(false),
       type(type),
@@ -73,7 +71,7 @@
       typed_count(match.typed_count),
       deletable(match.deletable),
       fill_into_edit(match.fill_into_edit),
-      inline_autocomplete_offset(match.inline_autocomplete_offset),
+      inline_autocompletion(match.inline_autocompletion),
       destination_url(match.destination_url),
       stripped_destination_url(match.stripped_destination_url),
       contents(match.contents),
@@ -107,7 +105,7 @@
   typed_count = match.typed_count;
   deletable = match.deletable;
   fill_into_edit = match.fill_into_edit;
-  inline_autocomplete_offset = match.inline_autocomplete_offset;
+  inline_autocompletion = match.inline_autocompletion;
   destination_url = match.destination_url;
   stripped_destination_url = match.stripped_destination_url;
   contents = match.contents;
diff --git a/chrome/browser/autocomplete/autocomplete_match.h b/chrome/browser/autocomplete/autocomplete_match.h
index 4d4ca47..224bf99 100644
--- a/chrome/browser/autocomplete/autocomplete_match.h
+++ b/chrome/browser/autocomplete/autocomplete_match.h
@@ -246,10 +246,9 @@
   // for search suggestions, this would just be the search terms.
   string16 fill_into_edit;
 
-  // The position within fill_into_edit from which we'll display the inline
-  // autocomplete string.  This will be string16::npos if this match should
-  // not be inline autocompleted.
-  size_t inline_autocomplete_offset;
+  // The inline autocompletion to display after the user's typing in the
+  // omnibox, if this match becomes the default match.  It may be empty.
+  string16 inline_autocompletion;
 
   // The URL to actually load when the autocomplete item is selected. This URL
   // should be canonical so we can compare URLs with strcmp to avoid dupes.
diff --git a/chrome/browser/autocomplete/contact_provider_chromeos.cc b/chrome/browser/autocomplete/contact_provider_chromeos.cc
index 7644eae..afa14ba 100644
--- a/chrome/browser/autocomplete/contact_provider_chromeos.cc
+++ b/chrome/browser/autocomplete/contact_provider_chromeos.cc
@@ -227,7 +227,6 @@
     const AutocompleteInput& input,
     const ContactData& contact) {
   AutocompleteMatch match(this, 0, false, AutocompleteMatchType::CONTACT);
-  match.inline_autocomplete_offset = string16::npos;
   match.contents = contact.full_name;
   match.fill_into_edit = match.contents;
   match.relevance = kBaseRelevance +
diff --git a/chrome/browser/autocomplete/extension_app_provider.cc b/chrome/browser/autocomplete/extension_app_provider.cc
index 003cdac..06f0daf 100644
--- a/chrome/browser/autocomplete/extension_app_provider.cc
+++ b/chrome/browser/autocomplete/extension_app_provider.cc
@@ -79,7 +79,6 @@
   match.fill_into_edit =
       app.should_match_against_launch_url ? app.launch_url : input.text();
   match.destination_url = GURL(app.launch_url);
-  match.inline_autocomplete_offset = string16::npos;
   match.contents = AutocompleteMatch::SanitizeString(app.name);
   AutocompleteMatch::ClassifyLocationInString(name_match_index,
       input.text().length(), app.name.length(), ACMatchClassification::NONE,
diff --git a/chrome/browser/autocomplete/history_quick_provider.cc b/chrome/browser/autocomplete/history_quick_provider.cc
index 073aa18..fc74e13 100644
--- a/chrome/browser/autocomplete/history_quick_provider.cc
+++ b/chrome/browser/autocomplete/history_quick_provider.cc
@@ -272,17 +272,18 @@
   match.contents_class =
       SpansFromTermMatch(new_matches, match.contents.length(), true);
 
-  if (!history_match.can_inline) {
-    match.inline_autocomplete_offset = string16::npos;
-  } else {
+  if (history_match.can_inline) {
     DCHECK(!new_matches.empty());
-    match.inline_autocomplete_offset = new_matches[0].offset +
+    size_t inline_autocomplete_offset = new_matches[0].offset +
         new_matches[0].length;
-    // The following will happen if the user has typed an URL with a scheme
-    // and the last character typed is a slash because that slash is removed
-    // by the FormatURLWithOffsets call above.
-    if (match.inline_autocomplete_offset > match.fill_into_edit.length())
-      match.inline_autocomplete_offset = match.fill_into_edit.length();
+    // |inline_autocomplete_offset| may be beyond the end of the
+    // |fill_into_edit| if the user has typed an URL with a scheme and the
+    // last character typed is a slash.  That slash is removed by the
+    // FormatURLWithOffsets call above.
+    if (inline_autocomplete_offset < match.fill_into_edit.length()) {
+      match.inline_autocompletion =
+          match.fill_into_edit.substr(inline_autocomplete_offset);
+    }
   }
 
   // Format the description autocomplete presentation.
diff --git a/chrome/browser/autocomplete/history_quick_provider_unittest.cc b/chrome/browser/autocomplete/history_quick_provider_unittest.cc
index 7e28403..fe50366 100644
--- a/chrome/browser/autocomplete/history_quick_provider_unittest.cc
+++ b/chrome/browser/autocomplete/history_quick_provider_unittest.cc
@@ -295,11 +295,11 @@
         << "' but we expected '" << expected_fill_into_edit << "'.";
     size_t text_pos = expected_fill_into_edit.find(text);
     ASSERT_NE(string16::npos, text_pos);
-    EXPECT_EQ(text_pos + text.size(),
-              ac_matches_[0].inline_autocomplete_offset);
+    EXPECT_EQ(ac_matches_[0].fill_into_edit.substr(text_pos + text.size()),
+              ac_matches_[0].inline_autocompletion);
   } else {
     // When the top scorer is not inline-able autocomplete offset must be npos.
-    EXPECT_EQ(string16::npos, ac_matches_[0].inline_autocomplete_offset);
+    EXPECT_TRUE(ac_matches_[0].inline_autocompletion.empty());
     // Also, the score must be too low to be inlineable.
     EXPECT_LT(ac_matches_[0].relevance,
               AutocompleteResult::kLowestDefaultScore);
diff --git a/chrome/browser/autocomplete/history_url_provider.cc b/chrome/browser/autocomplete/history_url_provider.cc
index 4c51b30..48c56a1 100644
--- a/chrome/browser/autocomplete/history_url_provider.cc
+++ b/chrome/browser/autocomplete/history_url_provider.cc
@@ -349,8 +349,8 @@
     match.fill_into_edit =
         AutocompleteInput::FormattedStringWithEquivalentMeaning(url,
                                                                 display_string);
-    // NOTE: Don't set match.inline_autocomplete_offset (to allow inline
-    // autocompletion) here, it's surprising and annoying.
+    // NOTE: Don't set match.inline_autocompletion to something non-empty here;
+    // it's surprising and annoying.
 
     // Try to highlight "innermost" match location.  If we fix up "w" into
     // "www.w.com", we want to highlight the fifth character, not the first.
@@ -1059,10 +1059,12 @@
           net::FormatUrl(info.url(), languages, format_types,
                          net::UnescapeRule::SPACES, NULL, NULL,
                          &inline_autocomplete_offset));
-  if (!params->prevent_inline_autocomplete)
-    match.inline_autocomplete_offset = inline_autocomplete_offset;
-  DCHECK((match.inline_autocomplete_offset == string16::npos) ||
-         (match.inline_autocomplete_offset <= match.fill_into_edit.length()));
+  if (!params->prevent_inline_autocomplete &&
+      (inline_autocomplete_offset != string16::npos)) {
+    DCHECK(inline_autocomplete_offset <= match.fill_into_edit.length());
+    match.inline_autocompletion =
+        match.fill_into_edit.substr(inline_autocomplete_offset);
+  }
 
   size_t match_start = history_match.input_location;
   match.contents = net::FormatUrl(info.url(), languages,
diff --git a/chrome/browser/autocomplete/history_url_provider_unittest.cc b/chrome/browser/autocomplete/history_url_provider_unittest.cc
index c35b45f..b26c9a0 100644
--- a/chrome/browser/autocomplete/history_url_provider_unittest.cc
+++ b/chrome/browser/autocomplete/history_url_provider_unittest.cc
@@ -183,8 +183,6 @@
                    expected_urls, num_results, &type);
   }
 
-  void RunAdjustOffsetTest(const string16 text, size_t expected_offset);
-
   content::TestBrowserThreadBundle thread_bundle_;
   ACMatches matches_;
   scoped_ptr<TestingProfile> profile_;
@@ -286,19 +284,6 @@
     EXPECT_EQ(expected_urls[i], matches_[i].destination_url.spec());
 }
 
-void HistoryURLProviderTest::RunAdjustOffsetTest(const string16 text,
-                                                 size_t expected_offset) {
-  AutocompleteInput input(text, string16::npos, string16(), GURL(), false,
-                          false, true, AutocompleteInput::ALL_MATCHES);
-  autocomplete_->Start(input, false);
-  if (!autocomplete_->done())
-    base::MessageLoop::current()->Run();
-
-  matches_ = autocomplete_->matches();
-  ASSERT_GE(matches_.size(), 1U) << "Input text: " << text;
-  EXPECT_EQ(expected_offset, matches_[0].inline_autocomplete_offset);
-}
-
 TEST_F(HistoryURLProviderTest, PromoteShorterURLs) {
   // Test that hosts get synthesized below popular pages.
   const std::string expected_nonsynth[] = {
@@ -490,7 +475,8 @@
   const std::string fixup_1[] = {"file:///C:/foo.txt"};
   ASSERT_NO_FATAL_FAILURE(RunTest(input_1, string16(), false, fixup_1,
                                   arraysize(fixup_1)));
-  EXPECT_EQ(input_1.length(), matches_.front().inline_autocomplete_offset);
+  EXPECT_EQ(ASCIIToUTF16("///C:/foo.txt"),
+            matches_.front().inline_autocompletion);
 
   // Fixing up "http:/" should result in an inline autocomplete offset of just
   // after "http:/", not just after "http:".
@@ -502,7 +488,8 @@
   };
   ASSERT_NO_FATAL_FAILURE(RunTest(input_2, string16(), false, fixup_2,
                                   arraysize(fixup_2)));
-  EXPECT_EQ(input_2.length(), matches_.front().inline_autocomplete_offset);
+  EXPECT_EQ(ASCIIToUTF16("/bogussite.com/a"),
+            matches_.front().inline_autocompletion);
 
   // Adding a TLD to a small number like "56" should result in "www.56.com"
   // rather than "0.0.0.56.com".
@@ -522,12 +509,6 @@
           arraysize(fixup_5));
 }
 
-TEST_F(HistoryURLProviderTest, AdjustOffset) {
-  RunAdjustOffsetTest(WideToUTF16(L"http://www.\uAD50\uC721"), 13);
-  RunAdjustOffsetTest(ASCIIToUTF16("http://spaces.com/path%20with%20spa"), 31);
-  RunAdjustOffsetTest(ASCIIToUTF16("http://ms/c++ s"), 15);
-}
-
 // Make sure the results for the input 'p' don't change between the first and
 // second passes.
 TEST_F(HistoryURLProviderTest, EmptyVisits) {
@@ -580,7 +561,7 @@
   // None of the matches should attempt to autocomplete.
   matches_ = autocomplete_->matches();
   for (size_t i = 0; i < matches_.size(); ++i)
-    EXPECT_EQ(string16::npos, matches_[i].inline_autocomplete_offset);
+    EXPECT_TRUE(matches_[i].inline_autocompletion.empty());
 }
 
 TEST_F(HistoryURLProviderTest, TreatEmailsAsSearches) {
diff --git a/chrome/browser/autocomplete/keyword_provider.cc b/chrome/browser/autocomplete/keyword_provider.cc
index 10ae975..dd2959e 100644
--- a/chrome/browser/autocomplete/keyword_provider.cc
+++ b/chrome/browser/autocomplete/keyword_provider.cc
@@ -446,12 +446,11 @@
   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
+  // If we wanted to set |result.inline_autocompletion| 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.
diff --git a/chrome/browser/autocomplete/search_provider.cc b/chrome/browser/autocomplete/search_provider.cc
index 6f22d09..8806491 100644
--- a/chrome/browser/autocomplete/search_provider.cc
+++ b/chrome/browser/autocomplete/search_provider.cc
@@ -326,8 +326,7 @@
     match.fill_into_edit.append(match.keyword + char16(' '));
   if (!input.prevent_inline_autocomplete() &&
       StartsWith(query_string, input_text, false)) {
-    match.inline_autocomplete_offset =
-        match.fill_into_edit.length() + input_text.length();
+    match.inline_autocompletion = query_string.substr(input_text.length());
   }
   match.fill_into_edit.append(query_string);
 
@@ -1076,7 +1075,7 @@
   return
       matches_.front().type != AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED &&
       matches_.front().type != AutocompleteMatchType::SEARCH_OTHER_ENGINE &&
-      matches_.front().inline_autocomplete_offset == string16::npos &&
+      matches_.front().inline_autocompletion.empty() &&
       matches_.front().fill_into_edit != input_.text();
 }
 
@@ -1446,10 +1445,12 @@
           net::FormatUrl(navigation.url(), languages, format_types,
                          net::UnescapeRule::SPACES, NULL, NULL,
                          &inline_autocomplete_offset));
-  if (!input_.prevent_inline_autocomplete())
-    match.inline_autocomplete_offset = inline_autocomplete_offset;
-  DCHECK((match.inline_autocomplete_offset == string16::npos) ||
-         (match.inline_autocomplete_offset <= match.fill_into_edit.length()));
+  if (!input_.prevent_inline_autocomplete() &&
+      (inline_autocomplete_offset != string16::npos)) {
+    DCHECK(inline_autocomplete_offset <= match.fill_into_edit.length());
+    match.inline_autocompletion =
+        match.fill_into_edit.substr(inline_autocomplete_offset);
+  }
 
   match.contents = net::FormatUrl(navigation.url(), languages,
       format_types, net::UnescapeRule::SPACES, NULL, NULL, &match_start);
diff --git a/chrome/browser/autocomplete/search_provider_unittest.cc b/chrome/browser/autocomplete/search_provider_unittest.cc
index 2551ca2..b32cadc 100644
--- a/chrome/browser/autocomplete/search_provider_unittest.cc
+++ b/chrome/browser/autocomplete/search_provider_unittest.cc
@@ -666,8 +666,8 @@
   AutocompleteMatch term_match;
   EXPECT_TRUE(FindMatchWithDestination(term_url, &term_match));
   EXPECT_GT(term_match.relevance, wyt_match.relevance);
-  EXPECT_EQ(1u, term_match.inline_autocomplete_offset);
   EXPECT_EQ(ASCIIToUTF16("FOO"), term_match.fill_into_edit);
+  EXPECT_EQ(ASCIIToUTF16("OO"), term_match.inline_autocompletion);
 }
 
 // Verifies AutocompleteControllers return results (including keyword
@@ -895,108 +895,109 @@
   struct {
     const std::string json;
     const std::string matches[4];
+    const std::string inline_autocompletion;
   } cases[] = {
     // Ensure that suggestrelevance scores reorder matches.
     { "[\"a\",[\"b\", \"c\"],[],[],{\"google:suggestrelevance\":[1, 2]}]",
-      { "a", "c", "b", kNotApplicable } },
+      { "a", "c", "b", kNotApplicable }, std::string() },
     { "[\"a\",[\"http://b.com\", \"http://c.com\"],[],[],"
        "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
         "\"google:suggestrelevance\":[1, 2]}]",
-      { "a", "c.com", "b.com", kNotApplicable } },
+      { "a", "c.com", "b.com", kNotApplicable }, std::string() },
 
     // Without suggested relevance scores, we should only allow one
     // navsuggest result to be be displayed.
     { "[\"a\",[\"http://b.com\", \"http://c.com\"],[],[],"
        "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"]}]",
-      { "a", "b.com", kNotApplicable, kNotApplicable } },
+      { "a", "b.com", kNotApplicable, kNotApplicable }, std::string() },
 
     // Ensure that verbatimrelevance scores reorder or suppress verbatim.
     // Negative values will have no effect; the calculated value will be used.
     { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":9999,"
                              "\"google:suggestrelevance\":[9998]}]",
-      { "a", "a1", kNotApplicable, kNotApplicable } },
+      { "a", "a1", kNotApplicable, kNotApplicable }, std::string() },
     { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":9998,"
                              "\"google:suggestrelevance\":[9999]}]",
-      { "a1", "a", kNotApplicable, kNotApplicable } },
+      { "a1", "a", kNotApplicable, kNotApplicable }, "1" },
     { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":0,"
                              "\"google:suggestrelevance\":[9999]}]",
-      { "a1", kNotApplicable, kNotApplicable, kNotApplicable } },
+      { "a1", kNotApplicable, kNotApplicable, kNotApplicable }, "1" },
     { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":-1,"
                              "\"google:suggestrelevance\":[9999]}]",
-      { "a1", "a", kNotApplicable, kNotApplicable } },
+      { "a1", "a", kNotApplicable, kNotApplicable }, "1" },
     { "[\"a\",[\"http://a.com\"],[],[],"
        "{\"google:suggesttype\":[\"NAVIGATION\"],"
         "\"google:verbatimrelevance\":9999,"
         "\"google:suggestrelevance\":[9998]}]",
-      { "a", "a.com", kNotApplicable, kNotApplicable } },
+      { "a", "a.com", kNotApplicable, kNotApplicable }, std::string() },
     { "[\"a\",[\"http://a.com\"],[],[],"
        "{\"google:suggesttype\":[\"NAVIGATION\"],"
         "\"google:verbatimrelevance\":9998,"
         "\"google:suggestrelevance\":[9999]}]",
-      { "a.com", "a", kNotApplicable, kNotApplicable } },
+      { "a.com", "a", kNotApplicable, kNotApplicable }, ".com" },
     { "[\"a\",[\"http://a.com\"],[],[],"
        "{\"google:suggesttype\":[\"NAVIGATION\"],"
         "\"google:verbatimrelevance\":0,"
         "\"google:suggestrelevance\":[9999]}]",
-      { "a.com", kNotApplicable, kNotApplicable, kNotApplicable } },
+      { "a.com", kNotApplicable, kNotApplicable, kNotApplicable }, ".com" },
     { "[\"a\",[\"http://a.com\"],[],[],"
        "{\"google:suggesttype\":[\"NAVIGATION\"],"
         "\"google:verbatimrelevance\":-1,"
         "\"google:suggestrelevance\":[9999]}]",
-      { "a.com", "a", kNotApplicable, kNotApplicable } },
+      { "a.com", "a", kNotApplicable, kNotApplicable }, ".com" },
 
     // Ensure that both types of relevance scores reorder matches together.
     { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[9999, 9997],"
                                      "\"google:verbatimrelevance\":9998}]",
-      { "a1", "a", "a2", kNotApplicable } },
+      { "a1", "a", "a2", kNotApplicable }, "1" },
 
     // Ensure that only inlinable matches may be ranked as the highest result.
     // Ignore all suggested relevance scores if this constraint is violated.
     { "[\"a\",[\"b\"],[],[],{\"google:suggestrelevance\":[9999]}]",
-      { "a", "b", kNotApplicable, kNotApplicable } },
+      { "a", "b", kNotApplicable, kNotApplicable }, std::string() },
     { "[\"a\",[\"b\"],[],[],{\"google:suggestrelevance\":[9999],"
                             "\"google:verbatimrelevance\":0}]",
-      { "a", "b", kNotApplicable, kNotApplicable } },
+      { "a", "b", kNotApplicable, kNotApplicable }, std::string() },
     { "[\"a\",[\"http://b.com\"],[],[],"
        "{\"google:suggesttype\":[\"NAVIGATION\"],"
         "\"google:suggestrelevance\":[9999]}]",
-      { "a", "b.com", kNotApplicable, kNotApplicable } },
+      { "a", "b.com", kNotApplicable, kNotApplicable }, std::string() },
     { "[\"a\",[\"http://b.com\"],[],[],"
        "{\"google:suggesttype\":[\"NAVIGATION\"],"
         "\"google:suggestrelevance\":[9999],"
         "\"google:verbatimrelevance\":0}]",
-      { "a", "b.com", kNotApplicable, kNotApplicable } },
+      { "a", "b.com", kNotApplicable, kNotApplicable }, std::string() },
 
     // Ensure that the top result is ranked as highly as calculated verbatim.
     // Ignore the suggested verbatim relevance if this constraint is violated.
     { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":0}]",
-      { "a", "a1", kNotApplicable, kNotApplicable } },
+      { "a", "a1", kNotApplicable, kNotApplicable }, std::string() },
     { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":1}]",
-      { "a", "a1", kNotApplicable, kNotApplicable } },
+      { "a", "a1", kNotApplicable, kNotApplicable }, std::string() },
     { "[\"a\",[\"a1\"],[],[],{\"google:suggestrelevance\":[1],"
                              "\"google:verbatimrelevance\":0}]",
-      { "a", "a1", kNotApplicable, kNotApplicable } },
+      { "a", "a1", kNotApplicable, kNotApplicable }, std::string() },
     { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[1, 2],"
                                      "\"google:verbatimrelevance\":0}]",
-      { "a", "a2", "a1", kNotApplicable } },
+      { "a", "a2", "a1", kNotApplicable }, std::string() },
     { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[1, 3],"
       "\"google:verbatimrelevance\":2}]",
-      { "a", "a2", "a1", kNotApplicable } },
+      { "a", "a2", "a1", kNotApplicable }, std::string() },
     { "[\"a\",[\"http://a.com\"],[],[],"
        "{\"google:suggesttype\":[\"NAVIGATION\"],"
         "\"google:suggestrelevance\":[1],"
         "\"google:verbatimrelevance\":0}]",
-      { "a", "a.com", kNotApplicable, kNotApplicable } },
+      { "a", "a.com", kNotApplicable, kNotApplicable }, std::string() },
     { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
        "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
         "\"google:suggestrelevance\":[1, 2],"
         "\"google:verbatimrelevance\":0}]",
-      { "a", "a2.com", "a1.com", kNotApplicable } },
+      { "a", "a2.com", "a1.com", kNotApplicable }, std::string() },
 
     // Ensure that all suggestions are considered, regardless of order.
     { "[\"a\",[\"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\"],[],[],"
        "{\"google:suggestrelevance\":[1, 2, 3, 4, 5, 6, 7]}]",
-      { "a", "h", "g", "f" } },
+      { "a", "h", "g", "f" }, std::string() },
     { "[\"a\",[\"http://b.com\", \"http://c.com\", \"http://d.com\","
               "\"http://e.com\", \"http://f.com\", \"http://g.com\","
               "\"http://h.com\"],[],[],"
@@ -1005,37 +1006,37 @@
                                 "\"NAVIGATION\", \"NAVIGATION\","
                                 "\"NAVIGATION\"],"
         "\"google:suggestrelevance\":[1, 2, 3, 4, 5, 6, 7]}]",
-      { "a", "h.com", "g.com", "f.com" } },
+      { "a", "h.com", "g.com", "f.com" }, std::string() },
 
     // Ensure that incorrectly sized suggestion relevance lists are ignored.
     { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[1]}]",
-      { "a", "a1", "a2", kNotApplicable } },
+      { "a", "a1", "a2", kNotApplicable }, std::string() },
     { "[\"a\",[\"a1\"],[],[],{\"google:suggestrelevance\":[9999, 1]}]",
-      { "a", "a1", kNotApplicable, kNotApplicable } },
+      { "a", "a1", kNotApplicable, kNotApplicable }, std::string() },
     { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
        "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
         "\"google:suggestrelevance\":[1]}]",
-      { "a", "a1.com", kNotApplicable, kNotApplicable } },
+      { "a", "a1.com", kNotApplicable, kNotApplicable }, std::string() },
     { "[\"a\",[\"http://a1.com\"],[],[],"
        "{\"google:suggesttype\":[\"NAVIGATION\"],"
        "\"google:suggestrelevance\":[9999, 1]}]",
-      { "a", "a1.com", kNotApplicable, kNotApplicable } },
+      { "a", "a1.com", kNotApplicable, kNotApplicable }, std::string() },
 
     // Ensure that all 'verbatim' results are merged with their maximum score.
     { "[\"a\",[\"a\", \"a1\", \"a2\"],[],[],"
        "{\"google:suggestrelevance\":[9998, 9997, 9999]}]",
-      { "a2", "a", "a1", kNotApplicable } },
+      { "a2", "a", "a1", kNotApplicable }, "2" },
     { "[\"a\",[\"a\", \"a1\", \"a2\"],[],[],"
        "{\"google:suggestrelevance\":[9998, 9997, 9999],"
         "\"google:verbatimrelevance\":0}]",
-      { "a2", "a", "a1", kNotApplicable } },
+      { "a2", "a", "a1", kNotApplicable }, "2" },
 
     // Ensure that verbatim is always generated without other suggestions.
     // TODO(msw): Ensure verbatimrelevance is respected (except suppression).
     { "[\"a\",[],[],[],{\"google:verbatimrelevance\":1}]",
-      { "a", kNotApplicable, kNotApplicable, kNotApplicable } },
+      { "a", kNotApplicable, kNotApplicable, kNotApplicable }, std::string() },
     { "[\"a\",[],[],[],{\"google:verbatimrelevance\":0}]",
-      { "a", kNotApplicable, kNotApplicable, kNotApplicable } },
+      { "a", kNotApplicable, kNotApplicable, kNotApplicable }, std::string() },
   };
 
   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) {
@@ -1052,8 +1053,8 @@
     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_EQ(ASCIIToUTF16(cases[i].inline_autocompletion),
+              matches[0].inline_autocompletion) << description;
     EXPECT_GE(matches[0].relevance, 1300) << description;
 
     size_t j = 0;
@@ -1083,6 +1084,7 @@
       const std::string contents;
       const bool from_keyword;
     } matches[5];
+    const std::string inline_autocompletion;
   } cases[] = {
     // Ensure that suggest relevance scores reorder matches and that
     // the keyword verbatim (lacking a suggested verbatim score) beats
@@ -1092,7 +1094,8 @@
         { "k a", false },
         { "c", true },
         { "b", true },
-        { kNotApplicable, false } } },
+        { kNotApplicable, false } },
+      std::string() },
     // Again, check that relevance scores reorder matches, just this
     // time with navigation matches.  This also checks that with
     // suggested relevance scores we allow multiple navsuggest results.
@@ -1109,7 +1112,8 @@
         { "d", true },
         { "c.com", false },
         { "b.com", false },
-        { "k a", false }, } },
+        { "k a", false }, },
+      std::string() },
 
     // Without suggested relevance scores, we should only allow one
     // navsuggest result to be be displayed.
@@ -1119,7 +1123,8 @@
         { "b.com", false },
         { "k a", false },
         { kNotApplicable, false },
-        { kNotApplicable, false } } },
+        { kNotApplicable, false } },
+      std::string() },
 
     // Ensure that verbatimrelevance scores reorder or suppress verbatim.
     // Negative values will have no effect; the calculated value will be used.
@@ -1129,28 +1134,32 @@
         { "a1", true },
         { "k a", false },
         { kNotApplicable, false },
-        { kNotApplicable, false } } },
+        { kNotApplicable, false } },
+      std::string() },
     { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":9998,"
                              "\"google:suggestrelevance\":[9999]}]",
       { { "a1", true },
         { "a", true },
         { "k a", false },
         { kNotApplicable, false },
-        { kNotApplicable, false } } },
+        { kNotApplicable, false } },
+      "1" },
     { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":0,"
                              "\"google:suggestrelevance\":[9999]}]",
       { { "a1", true },
         { "k a", false },
         { kNotApplicable, false },
         { kNotApplicable, false },
-        { kNotApplicable, false } } },
+        { kNotApplicable, false } },
+      "1" },
     { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":-1,"
                              "\"google:suggestrelevance\":[9999]}]",
       { { "a1", true },
         { "a", true },
         { "k a", false },
         { kNotApplicable, false },
-        { kNotApplicable, false } } },
+        { kNotApplicable, false } },
+      "1" },
     { "[\"a\",[\"http://a.com\"],[],[],"
        "{\"google:suggesttype\":[\"NAVIGATION\"],"
         "\"google:verbatimrelevance\":9999,"
@@ -1159,7 +1168,8 @@
         { "a.com", false },
         { "k a", false },
         { kNotApplicable, false },
-        { kNotApplicable, false } } },
+        { kNotApplicable, false } },
+      std::string() },
 
     // Ensure that both types of relevance scores reorder matches together.
     { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[9999, 9997],"
@@ -1168,7 +1178,8 @@
         { "a", true },
         { "a2", true },
         { "k a", false },
-        { kNotApplicable, false } } },
+        { kNotApplicable, false } },
+      "1" },
 
     // Ensure that only inlinable matches may be ranked as the highest result.
     // Ignore all suggested relevance scores if this constraint is violated.
@@ -1177,14 +1188,16 @@
         { "b", true },
         { "k a", false },
         { kNotApplicable, false },
-        { kNotApplicable, false } } },
+        { kNotApplicable, false } },
+      std::string() },
     { "[\"a\",[\"b\"],[],[],{\"google:suggestrelevance\":[9999],"
                             "\"google:verbatimrelevance\":0}]",
       { { "a", true },
         { "b", true },
         { "k a", false },
         { kNotApplicable, false },
-        { kNotApplicable, false } } },
+        { kNotApplicable, false } },
+      std::string() },
     { "[\"a\",[\"http://b.com\"],[],[],"
        "{\"google:suggesttype\":[\"NAVIGATION\"],"
         "\"google:suggestrelevance\":[9999]}]",
@@ -1192,7 +1205,8 @@
         { "b.com", false },
         { "k a", false },
         { kNotApplicable, false },
-        { kNotApplicable, false } } },
+        { kNotApplicable, false } },
+      std::string() },
     { "[\"a\",[\"http://b.com\"],[],[],"
        "{\"google:suggesttype\":[\"NAVIGATION\"],"
         "\"google:suggestrelevance\":[9999],"
@@ -1201,7 +1215,8 @@
         { "b.com", false },
         { "k a", false },
         { kNotApplicable, false },
-        { kNotApplicable, false } } },
+        { kNotApplicable, false } },
+      std::string() },
 
     // Ensure that the top result is ranked as highly as calculated verbatim.
     // Ignore the suggested verbatim relevance if this constraint is violated.
@@ -1212,13 +1227,15 @@
         { "a1", true },
         { "k a", false },
         { kNotApplicable, false },
-        { kNotApplicable, false } } },
+        { kNotApplicable, false } },
+      std::string() },
     { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":1}]",
       { { "a", true },
         { "a1", true },
         { "k a", false },
         { kNotApplicable, false },
-        { kNotApplicable, false } } },
+        { kNotApplicable, false } },
+      std::string() },
     // Continuing the same category of tests, but make sure we keep the
     // suggested relevance scores even as we discard the verbatim relevance
     // scores.
@@ -1228,21 +1245,24 @@
         { "k a", false },
         { "a1", true },
         { kNotApplicable, false },
-        { kNotApplicable, false } } },
+        { kNotApplicable, false } },
+      std::string() },
     { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[1, 2],"
                                      "\"google:verbatimrelevance\":0}]",
       { { "a", true },
         { "k a", false },
         { "a2", true },
         { "a1", true },
-        { kNotApplicable, false } } },
+        { kNotApplicable, false } },
+      std::string() },
     { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[1, 3],"
       "\"google:verbatimrelevance\":2}]",
       { { "a", true },
         { "k a", false },
         { "a2", true },
         { "a1", true },
-        { kNotApplicable, false } } },
+        { kNotApplicable, false } },
+      std::string() },
 
     // Ensure that all suggestions are considered, regardless of order.
     { "[\"a\",[\"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\"],[],[],"
@@ -1251,7 +1271,8 @@
         { "k a", false },
         { "h", true },
         { "g", true },
-        { "f", true } } },
+        { "f", true } },
+      std::string() },
     { "[\"a\",[\"http://b.com\", \"http://c.com\", \"http://d.com\","
               "\"http://e.com\", \"http://f.com\", \"http://g.com\","
               "\"http://h.com\"],[],[],"
@@ -1264,7 +1285,8 @@
         { "k a", false },
         { "h.com", false },
         { "g.com", false },
-        { "f.com", false } } },
+        { "f.com", false } },
+      std::string() },
 
     // Ensure that incorrectly sized suggestion relevance lists are ignored.
     // Note that keyword suggestions by default (not in suggested relevance
@@ -1274,13 +1296,15 @@
         { "a1", true },
         { "a2", true },
         { "k a", false },
-        { kNotApplicable, false } } },
+        { kNotApplicable, false } },
+      std::string() },
     { "[\"a\",[\"a1\"],[],[],{\"google:suggestrelevance\":[9999, 1]}]",
       { { "a", true },
         { "a1", true },
         { "k a", false },
         { kNotApplicable, false },
-        { kNotApplicable, false } } },
+        { kNotApplicable, false } },
+      std::string() },
     // In this case, ignored the suggested relevance scores means we keep
     // only one navsuggest result.
     { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
@@ -1290,7 +1314,8 @@
         { "a1.com", false },
         { "k a", false },
         { kNotApplicable, false },
-        { kNotApplicable, false } } },
+        { kNotApplicable, false } },
+      std::string() },
     { "[\"a\",[\"http://a1.com\"],[],[],"
        "{\"google:suggesttype\":[\"NAVIGATION\"],"
        "\"google:suggestrelevance\":[9999, 1]}]",
@@ -1298,7 +1323,8 @@
         { "a1.com", false },
         { "k a", false },
         { kNotApplicable, false },
-        { kNotApplicable, false } } },
+        { kNotApplicable, false } },
+      std::string() },
 
     // Ensure that all 'verbatim' results are merged with their maximum score.
     { "[\"a\",[\"a\", \"a1\", \"a2\"],[],[],"
@@ -1307,7 +1333,8 @@
         { "a", true },
         { "a1", true },
         { "k a", false },
-        { kNotApplicable, false } } },
+        { kNotApplicable, false } },
+      "2" },
     { "[\"a\",[\"a\", \"a1\", \"a2\"],[],[],"
        "{\"google:suggestrelevance\":[9998, 9997, 9999],"
         "\"google:verbatimrelevance\":0}]",
@@ -1315,7 +1342,8 @@
         { "a", true },
         { "a1", true },
         { "k a", false },
-        { kNotApplicable, false } } },
+        { kNotApplicable, false } },
+      "2" },
 
     // Ensure that verbatim is always generated without other suggestions.
     // TODO(mpearson): Ensure the value of verbatimrelevance is respected
@@ -1325,13 +1353,15 @@
         { "k a", false },
         { kNotApplicable, false },
         { kNotApplicable, false },
-        { kNotApplicable, false } } },
+        { kNotApplicable, false } },
+      std::string() },
     { "[\"a\",[],[],[],{\"google:verbatimrelevance\":0}]",
       { { "a", true },
         { "k a", false },
         { kNotApplicable, false },
         { kNotApplicable, false },
-        { kNotApplicable, false } } },
+        { kNotApplicable, false } },
+      std::string() },
 
     // Check that navsuggestions will be demoted below queries.
     // (Navsuggestions are not allowed to appear first.)  In the process,
@@ -1346,7 +1376,8 @@
         { "a2.com", false },
         { "a1.com", false },
         { "k a", false },
-        { kNotApplicable, false } } },
+        { kNotApplicable, false } },
+      std::string() },
     { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
        "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
         "\"google:verbatimrelevance\":9990,"
@@ -1355,7 +1386,8 @@
         { "a1.com", false },
         { "a2.com", false },
         { "k a", false },
-        { kNotApplicable, false } } },
+        { kNotApplicable, false } },
+      std::string() },
     // Check when navsuggest scores more than verbatim and there is query
     // suggestion but it scores lower.
     { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
@@ -1366,7 +1398,8 @@
         { "a2.com", false },
         { "a1.com", false },
         { "a3", true },
-        { "k a", false } } },
+        { "k a", false } },
+      std::string() },
     { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
        "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
         "\"google:verbatimrelevance\":9990,"
@@ -1375,7 +1408,8 @@
         { "a1.com", false },
         { "a2.com", false },
         { "a3", true },
-        { "k a", false } } },
+        { "k a", false } },
+      std::string() },
     // Check when navsuggest scores more than a query suggestion.  There is
     // a verbatim but it scores lower.
     { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
@@ -1386,7 +1420,8 @@
         { "a2.com", false },
         { "a1.com", false },
         { "a", true },
-        { "k a", false } } },
+        { "k a", false } },
+      "3" },
     { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
        "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
         "\"google:verbatimrelevance\":9990,"
@@ -1395,7 +1430,8 @@
         { "a1.com", false },
         { "a2.com", false },
         { "a", true },
-        { "k a", false } } },
+        { "k a", false } },
+      "3" },
     { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
        "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
         "\"google:verbatimrelevance\":0,"
@@ -1404,7 +1440,8 @@
         { "a2.com", false },
         { "a1.com", false },
         { "k a", false },
-        { kNotApplicable, false } } },
+        { kNotApplicable, false } },
+      "3" },
     { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
        "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
         "\"google:verbatimrelevance\":0,"
@@ -1413,7 +1450,8 @@
         { "a1.com", false },
         { "a2.com", false },
         { "k a", false },
-        { kNotApplicable, false } } },
+        { kNotApplicable, false } },
+      "3" },
     // Check when there is neither verbatim nor a query suggestion that,
     // because we can't demote navsuggestions below a query suggestion,
     // we abandon suggested relevance scores entirely.  One consequence is
@@ -1429,7 +1467,8 @@
         { "a2.com", false },
         { "k a", false },
         { kNotApplicable, false },
-        { kNotApplicable, false } } },
+        { kNotApplicable, false } },
+      std::string() },
     { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
        "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
         "\"google:verbatimrelevance\":0,"
@@ -1438,7 +1477,8 @@
         { "a1.com", false },
         { "k a", false },
         { kNotApplicable, false },
-        { kNotApplicable, false } } },
+        { kNotApplicable, false } },
+      std::string() },
     // More checks that everything works when it's not necessary to demote.
     { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
        "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
@@ -1448,7 +1488,8 @@
         { "a2.com", false },
         { "a1.com", false },
         { "a", true },
-        { "k a", false } } },
+        { "k a", false } },
+      "3" },
     { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
        "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
         "\"google:verbatimrelevance\":9990,"
@@ -1457,7 +1498,8 @@
         { "a1.com", false },
         { "a2.com", false },
         { "a", true },
-        { "k a", false } } },
+        { "k a", false } },
+      "3" },
   };
 
   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) {
@@ -1485,8 +1527,8 @@
     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_EQ(ASCIIToUTF16(cases[i].inline_autocompletion),
+              matches[0].inline_autocompletion) << description;
     EXPECT_GE(matches[0].relevance, 1300) << description;
 
     size_t j = 0;
@@ -1757,127 +1799,139 @@
     // Test the expected fill_into_edit, which may drop "http://".
     // Some cases do not trim "http://" to match from the start of the scheme.
     const std::string fill_into_edit;
-    size_t inline_offset;
+    const std::string inline_autocompletion;
   } cases[] = {
     // Do not inline matches that do not contain the input; trim http as needed.
     { "x",                    "http://www.abc.com",
-                                     "www.abc.com",  string16::npos },
+      "www.abc.com",  std::string() },
     { "https:",               "http://www.abc.com",
-                                     "www.abc.com",  string16::npos },
+                                     "www.abc.com",  std::string() },
     { "abc.com/",             "http://www.abc.com",
-                                     "www.abc.com",  string16::npos },
+                                     "www.abc.com",  std::string() },
     { "http://www.abc.com/a", "http://www.abc.com",
-                              "http://www.abc.com",  string16::npos },
+                              "http://www.abc.com",  std::string() },
     { "http://www.abc.com",   "https://www.abc.com",
-                              "https://www.abc.com", string16::npos },
+                              "https://www.abc.com", std::string() },
     { "http://abc.com",       "ftp://abc.com",
-                              "ftp://abc.com",       string16::npos },
+                              "ftp://abc.com",       std::string() },
     { "https://www.abc.com",  "http://www.abc.com",
-                                     "www.abc.com",  string16::npos },
+                                     "www.abc.com",  std::string() },
     { "ftp://abc.com",        "http://abc.com",
-                                     "abc.com",      string16::npos },
+                                     "abc.com",      std::string() },
 
     // Do not inline matches with invalid input prefixes; trim http as needed.
     { "ttp",                  "http://www.abc.com",
-                                     "www.abc.com", string16::npos },
+                                     "www.abc.com", std::string() },
     { "://w",                 "http://www.abc.com",
-                                     "www.abc.com", string16::npos },
+                                     "www.abc.com", std::string() },
     { "ww.",                  "http://www.abc.com",
-                                     "www.abc.com", string16::npos },
+                                     "www.abc.com", std::string() },
     { ".ab",                  "http://www.abc.com",
-                                     "www.abc.com", string16::npos },
+                                     "www.abc.com", std::string() },
     { "bc",                   "http://www.abc.com",
-                                     "www.abc.com", string16::npos },
+                                     "www.abc.com", std::string() },
     { ".com",                 "http://www.abc.com",
-                                     "www.abc.com", string16::npos },
+                                     "www.abc.com", std::string() },
 
     // Do not inline matches that omit input domain labels; trim http as needed.
     { "www.a",                "http://a.com",
-                                     "a.com",       string16::npos },
+                                     "a.com",       std::string() },
     { "http://www.a",         "http://a.com",
-                              "http://a.com",       string16::npos },
+                              "http://a.com",       std::string() },
     { "www.a",                "ftp://a.com",
-                              "ftp://a.com",        string16::npos },
+                              "ftp://a.com",        std::string() },
     { "ftp://www.a",          "ftp://a.com",
-                              "ftp://a.com",        string16::npos },
+                              "ftp://a.com",        std::string() },
 
     // Input matching but with nothing to inline will not yield an offset.
     { "abc.com",              "http://www.abc.com",
-                                     "www.abc.com", string16::npos },
+                                     "www.abc.com", std::string() },
     { "http://www.abc.com",   "http://www.abc.com",
-                              "http://www.abc.com", string16::npos },
+                              "http://www.abc.com", std::string() },
 
     // Inline matches when the input is a leading substring of the scheme.
     { "h",                    "http://www.abc.com",
-                              "http://www.abc.com", 1 },
+                              "http://www.abc.com", "ttp://www.abc.com" },
     { "http",                 "http://www.abc.com",
-                              "http://www.abc.com", 4 },
+                              "http://www.abc.com", "://www.abc.com" },
 
     // Inline matches when the input is a leading substring of the full URL.
     { "http:",                "http://www.abc.com",
-                              "http://www.abc.com", 5 },
+                              "http://www.abc.com", "//www.abc.com" },
     { "http://w",             "http://www.abc.com",
-                              "http://www.abc.com", 8 },
+                              "http://www.abc.com", "ww.abc.com" },
     { "http://www.",          "http://www.abc.com",
-                              "http://www.abc.com", 11 },
+                              "http://www.abc.com", "abc.com" },
     { "http://www.ab",        "http://www.abc.com",
-                              "http://www.abc.com", 13 },
+                              "http://www.abc.com", "c.com" },
     { "http://www.abc.com/p", "http://www.abc.com/path/file.htm?q=x#foo",
-                              "http://www.abc.com/path/file.htm?q=x#foo", 20 },
+                              "http://www.abc.com/path/file.htm?q=x#foo",
+                                                  "ath/file.htm?q=x#foo" },
     { "http://abc.com/p",     "http://abc.com/path/file.htm?q=x#foo",
-                              "http://abc.com/path/file.htm?q=x#foo",     16 },
+                              "http://abc.com/path/file.htm?q=x#foo",
+                                              "ath/file.htm?q=x#foo"},
 
     // Inline matches with valid URLPrefixes; only trim "http://".
     { "w",                    "http://www.abc.com",
-                                     "www.abc.com", 1 },
+                                     "www.abc.com", "ww.abc.com" },
     { "www.a",                "http://www.abc.com",
-                                     "www.abc.com", 5 },
+                                     "www.abc.com", "bc.com" },
     { "abc",                  "http://www.abc.com",
-                                     "www.abc.com", 7 },
+                                     "www.abc.com", ".com" },
     { "abc.c",                "http://www.abc.com",
-                                     "www.abc.com", 9 },
+                                     "www.abc.com", "om" },
     { "abc.com/p",            "http://www.abc.com/path/file.htm?q=x#foo",
-                                     "www.abc.com/path/file.htm?q=x#foo", 13 },
+                                     "www.abc.com/path/file.htm?q=x#foo",
+                                                  "ath/file.htm?q=x#foo" },
     { "abc.com/p",            "http://abc.com/path/file.htm?q=x#foo",
-                                     "abc.com/path/file.htm?q=x#foo",     9 },
+                                     "abc.com/path/file.htm?q=x#foo",
+                                              "ath/file.htm?q=x#foo" },
 
     // Inline matches using the maximal URLPrefix components.
     { "h",                    "http://help.com",
-                                     "help.com",     1 },
+                                     "help.com", "elp.com" },
     { "http",                 "http://http.com",
-                                     "http.com",     4 },
+                                     "http.com", ".com" },
     { "h",                    "http://www.help.com",
-                                     "www.help.com", 5 },
+                                     "www.help.com", "elp.com" },
     { "http",                 "http://www.http.com",
-                                     "www.http.com", 8 },
+                                     "www.http.com", ".com" },
     { "w",                    "http://www.www.com",
-                                     "www.www.com",  5 },
+                                     "www.www.com",  "ww.com" },
 
     // Test similar behavior for the ftp and https schemes.
     { "ftp://www.ab",         "ftp://www.abc.com/path/file.htm?q=x#foo",
-                              "ftp://www.abc.com/path/file.htm?q=x#foo",   12 },
+                              "ftp://www.abc.com/path/file.htm?q=x#foo",
+                                          "c.com/path/file.htm?q=x#foo" },
     { "www.ab",               "ftp://www.abc.com/path/file.htm?q=x#foo",
-                              "ftp://www.abc.com/path/file.htm?q=x#foo",   12 },
+                              "ftp://www.abc.com/path/file.htm?q=x#foo",
+                                          "c.com/path/file.htm?q=x#foo" },
     { "ab",                   "ftp://www.abc.com/path/file.htm?q=x#foo",
-                              "ftp://www.abc.com/path/file.htm?q=x#foo",   12 },
+                              "ftp://www.abc.com/path/file.htm?q=x#foo",
+                                          "c.com/path/file.htm?q=x#foo" },
     { "ab",                   "ftp://abc.com/path/file.htm?q=x#foo",
-                              "ftp://abc.com/path/file.htm?q=x#foo",       8 },
+                              "ftp://abc.com/path/file.htm?q=x#foo",
+                                      "c.com/path/file.htm?q=x#foo" },
     { "https://www.ab",       "https://www.abc.com/path/file.htm?q=x#foo",
-                              "https://www.abc.com/path/file.htm?q=x#foo", 14 },
+                              "https://www.abc.com/path/file.htm?q=x#foo",
+                                            "c.com/path/file.htm?q=x#foo" },
     { "www.ab",               "https://www.abc.com/path/file.htm?q=x#foo",
-                              "https://www.abc.com/path/file.htm?q=x#foo", 14 },
+                              "https://www.abc.com/path/file.htm?q=x#foo",
+                                            "c.com/path/file.htm?q=x#foo" },
     { "ab",                   "https://www.abc.com/path/file.htm?q=x#foo",
-                              "https://www.abc.com/path/file.htm?q=x#foo", 14 },
+                              "https://www.abc.com/path/file.htm?q=x#foo",
+                                            "c.com/path/file.htm?q=x#foo" },
     { "ab",                   "https://abc.com/path/file.htm?q=x#foo",
-                              "https://abc.com/path/file.htm?q=x#foo",     10 },
+                              "https://abc.com/path/file.htm?q=x#foo",
+                                        "c.com/path/file.htm?q=x#foo"},
 
     // Forced query input should inline and retain the "?" prefix.
     { "?http://www.ab",       "http://www.abc.com",
-                             "?http://www.abc.com", 14 },
+                             "?http://www.abc.com", "c.com" },
     { "?www.ab",              "http://www.abc.com",
-                                    "?www.abc.com", 7 },
+                                    "?www.abc.com", "c.com" },
     { "?ab",                  "http://www.abc.com",
-                                    "?www.abc.com", 7 },
+                                    "?www.abc.com", "c.com" },
   };
 
   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) {
@@ -1886,7 +1940,8 @@
         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].inline_autocompletion),
+              match.inline_autocompletion);
     EXPECT_EQ(ASCIIToUTF16(cases[i].fill_into_edit), match.fill_into_edit);
   }
 }
@@ -1901,14 +1956,14 @@
   // Check the offset and strings when inline autocompletion is allowed.
   QueryForInput(input, false, false);
   AutocompleteMatch match_inline(provider_->NavigationToMatch(result));
-  EXPECT_EQ(2U, match_inline.inline_autocomplete_offset);
   EXPECT_EQ(url, match_inline.fill_into_edit);
+  EXPECT_EQ(url.substr(2), match_inline.inline_autocompletion);
   EXPECT_EQ(url, match_inline.contents);
 
   // Check the same offset and strings when inline autocompletion is prevented.
   QueryForInput(input, true, false);
   AutocompleteMatch match_prevent(provider_->NavigationToMatch(result));
-  EXPECT_EQ(string16::npos, match_prevent.inline_autocomplete_offset);
+  EXPECT_TRUE(match_prevent.inline_autocompletion.empty());
   EXPECT_EQ(url, match_prevent.fill_into_edit);
   EXPECT_EQ(url, match_prevent.contents);
 }
@@ -1920,7 +1975,7 @@
       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("ow.com"), match.inline_autocompletion);
   EXPECT_EQ(ASCIIToUTF16("www.wow.com"), match.fill_into_edit);
   EXPECT_EQ(ASCIIToUTF16("www.wow.com"), match.contents);
 
diff --git a/chrome/browser/autocomplete/zero_suggest_provider.cc b/chrome/browser/autocomplete/zero_suggest_provider.cc
index 77c0e1f..da79e36 100644
--- a/chrome/browser/autocomplete/zero_suggest_provider.cc
+++ b/chrome/browser/autocomplete/zero_suggest_provider.cc
@@ -349,7 +349,6 @@
   match.fill_into_edit +=
       AutocompleteInput::FormattedStringWithEquivalentMeaning(navigation.url(),
           match.contents);
-  match.inline_autocomplete_offset = string16::npos;
 
   AutocompleteMatch::ClassifyLocationInString(string16::npos, 0,
       match.contents.length(), ACMatchClassification::URL,
@@ -458,7 +457,6 @@
       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/autofill/autofill_browsertest.cc b/chrome/browser/autofill/autofill_browsertest.cc
index fd2f89f..1b37b32 100644
--- a/chrome/browser/autofill/autofill_browsertest.cc
+++ b/chrome/browser/autofill/autofill_browsertest.cc
@@ -51,6 +51,10 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/keycodes/keyboard_codes.h"
 
+#if defined(OS_WIN) && defined(USE_ASH)
+#include "base/win/windows_version.h"
+#endif
+
 
 namespace autofill {
 
@@ -1177,6 +1181,12 @@
 // pass the Luhn test) the credit card info should not be saved into Autofill
 // preferences.
 IN_PROC_BROWSER_TEST_F(AutofillTest, InvalidCreditCardNumberIsNotAggregated) {
+#if defined(OS_WIN) && defined(USE_ASH)
+  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
+  if (base::win::GetVersion() >= base::win::VERSION_WIN8)
+    return;
+#endif
+
   ASSERT_TRUE(test_server()->Start());
   std::string card("4408 0412 3456 7890");
   ASSERT_FALSE(autofill::IsValidCreditCardNumber(ASCIIToUTF16(card)));
@@ -1192,6 +1202,12 @@
 // http://www.merriampark.com/anatomycc.htm
 IN_PROC_BROWSER_TEST_F(AutofillTest,
                        WhitespacesAndSeparatorCharsStrippedForValidCCNums) {
+#if defined(OS_WIN) && defined(USE_ASH)
+  // Disable this test in Metro+Ash for now (http://crbug.com/179830).
+  if (base::win::GetVersion() >= base::win::VERSION_WIN8)
+    return;
+#endif
+
   ASSERT_TRUE(test_server()->Start());
   SubmitCreditCard("Bob Smith", "4408 0412 3456 7893", "12", "2014");
   SubmitCreditCard("Jane Doe", "4417-1234-5678-9113", "10", "2013");
@@ -1396,6 +1412,12 @@
 // card infobar should not offer to save the credit card info. The credit card
 // number must be a valid Luhn number.
 IN_PROC_BROWSER_TEST_F(AutofillTest, CCInfoNotStoredWhenAutocompleteOff) {
+#if defined(OS_WIN) && defined(USE_ASH)
+  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
+  if (base::win::GetVersion() >= base::win::VERSION_WIN8)
+    return;
+#endif
+
   ASSERT_TRUE(test_server()->Start());
   FormMap data;
   data["CREDIT_CARD_NAME"] = "Bob Smith";
diff --git a/chrome/browser/autofill/autofill_cc_infobar_delegate.cc b/chrome/browser/autofill/autofill_cc_infobar_delegate.cc
index ff744d4..fd6cdd4 100644
--- a/chrome/browser/autofill/autofill_cc_infobar_delegate.cc
+++ b/chrome/browser/autofill/autofill_cc_infobar_delegate.cc
@@ -29,14 +29,6 @@
           infobar_service, metric_logger, save_card_callback)));
 }
 
-// static
-scoped_ptr<ConfirmInfoBarDelegate> AutofillCCInfoBarDelegate::CreateForTesting(
-    const AutofillMetrics* metric_logger,
-    const base::Closure& save_card_callback) {
-  return scoped_ptr<ConfirmInfoBarDelegate>(
-      new AutofillCCInfoBarDelegate(NULL, metric_logger, save_card_callback));
-}
-
 AutofillCCInfoBarDelegate::AutofillCCInfoBarDelegate(
     InfoBarService* infobar_service,
     const AutofillMetrics* metric_logger,
diff --git a/chrome/browser/autofill/autofill_cc_infobar_delegate.h b/chrome/browser/autofill/autofill_cc_infobar_delegate.h
index 4941864..6e36e2b 100644
--- a/chrome/browser/autofill/autofill_cc_infobar_delegate.h
+++ b/chrome/browser/autofill/autofill_cc_infobar_delegate.h
@@ -27,14 +27,20 @@
 // card information gathered from a form submission.
 class AutofillCCInfoBarDelegate : public ConfirmInfoBarDelegate {
  public:
-  // Creates an AutofillCCInfoBarDelegate and adds it to |infobar_service|.
+  // Creates an autofill credit card infobar delegate and adds it to
+  // |infobar_service|.
   static void Create(InfoBarService* infobar_service,
                      const AutofillMetrics* metric_logger,
                      const base::Closure& save_card_callback);
 
-  static scoped_ptr<ConfirmInfoBarDelegate> CreateForTesting(
+#if defined(UNIT_TEST)
+  static scoped_ptr<ConfirmInfoBarDelegate> Create(
       const AutofillMetrics* metric_logger,
-      const base::Closure& save_card_callback);
+      const base::Closure& save_card_callback) {
+    return scoped_ptr<ConfirmInfoBarDelegate>(
+        new AutofillCCInfoBarDelegate(NULL, metric_logger, save_card_callback));
+  }
+#endif
 
  private:
   AutofillCCInfoBarDelegate(InfoBarService* infobar_service,
diff --git a/chrome/browser/autofill/form_structure_browsertest.cc b/chrome/browser/autofill/form_structure_browsertest.cc
index e6babac..0666fa2 100644
--- a/chrome/browser/autofill/form_structure_browsertest.cc
+++ b/chrome/browser/autofill/form_structure_browsertest.cc
@@ -5,10 +5,12 @@
 #include <vector>
 
 #include "base/files/file_path.h"
+#include "base/path_service.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/common/chrome_paths.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "components/autofill/content/browser/autofill_driver_impl.h"
@@ -27,6 +29,13 @@
   return GURL(std::string("data:text/html;charset=utf-8,") + html);
 }
 
+const base::FilePath& GetTestDataDir() {
+  CR_DEFINE_STATIC_LOCAL(base::FilePath, dir, ());
+  if (dir.empty())
+    PathService::Get(chrome::DIR_TEST_DATA, &dir);
+  return dir;
+}
+
 }  // namespace
 
 // A data-driven test for verifying Autofill heuristics. Each input is an HTML
@@ -49,7 +58,8 @@
   DISALLOW_COPY_AND_ASSIGN(FormStructureBrowserTest);
 };
 
-FormStructureBrowserTest::FormStructureBrowserTest() {
+FormStructureBrowserTest::FormStructureBrowserTest()
+    : DataDrivenTest(GetTestDataDir()) {
 }
 
 FormStructureBrowserTest::~FormStructureBrowserTest() {
diff --git a/chrome/browser/automation/testing_automation_provider.cc b/chrome/browser/automation/testing_automation_provider.cc
index 53fa3e0..ea10c51 100644
--- a/chrome/browser/automation/testing_automation_provider.cc
+++ b/chrome/browser/automation/testing_automation_provider.cc
@@ -139,6 +139,7 @@
 #include "content/public/common/drop_data.h"
 #include "content/public/common/geoposition.h"
 #include "content/public/common/ssl_status.h"
+#include "content/public/common/webplugininfo.h"
 #include "extensions/browser/view_type_utils.h"
 #include "extensions/common/url_pattern.h"
 #include "extensions/common/url_pattern_set.h"
@@ -147,7 +148,6 @@
 #include "ui/base/events/event_constants.h"
 #include "ui/base/keycodes/keyboard_codes.h"
 #include "ui/base/ui_base_types.h"
-#include "webkit/plugins/webplugininfo.h"
 
 #if defined(ENABLE_CONFIGURATION_POLICY)
 #include "chrome/browser/policy/policy_service.h"
@@ -2125,24 +2125,25 @@
                                        infobar_index));
     return;
   }
-  InfoBarDelegate* infobar = infobar_service->infobar_at(infobar_index);
+  InfoBarDelegate* infobar_delegate =
+      infobar_service->infobar_at(infobar_index);
 
   if (action == "dismiss") {
-    infobar->InfoBarDismissed();
-    infobar_service->RemoveInfoBar(infobar);
+    infobar_delegate->InfoBarDismissed();
+    infobar_service->RemoveInfoBar(infobar_delegate);
     reply.SendSuccess(NULL);
     return;
   }
   if ((action == "accept") || (action == "cancel")) {
-    ConfirmInfoBarDelegate* delegate = infobar->AsConfirmInfoBarDelegate();
-    if (!delegate) {
+    ConfirmInfoBarDelegate* confirm_infobar_delegate =
+        infobar_delegate->AsConfirmInfoBarDelegate();
+    if (!confirm_infobar_delegate) {
       reply.SendError("Not a confirm infobar");
       return;
     }
-    bool remove_infobar = (action == "accept") ?
-        delegate->Accept() : delegate->Cancel();
-    if (remove_infobar)
-      infobar_service->RemoveInfoBar(infobar);
+    if ((action == "accept") ?
+        confirm_infobar_delegate->Accept() : confirm_infobar_delegate->Cancel())
+      infobar_service->RemoveInfoBar(infobar_delegate);
     reply.SendSuccess(NULL);
     return;
   }
@@ -3057,11 +3058,11 @@
     Browser* browser,
     DictionaryValue* args,
     IPC::Message* reply_message,
-    const std::vector<webkit::WebPluginInfo>& plugins) {
+    const std::vector<content::WebPluginInfo>& plugins) {
   PluginPrefs* plugin_prefs =
       PluginPrefs::GetForProfile(browser->profile()).get();
   ListValue* items = new ListValue;
-  for (std::vector<webkit::WebPluginInfo>::const_iterator it =
+  for (std::vector<content::WebPluginInfo>::const_iterator it =
            plugins.begin();
        it != plugins.end();
        ++it) {
@@ -3073,7 +3074,7 @@
     item->SetBoolean("enabled", plugin_prefs->IsPluginEnabled(*it));
     // Add info about mime types.
     ListValue* mime_types = new ListValue();
-    for (std::vector<webkit::WebPluginMimeType>::const_iterator type_it =
+    for (std::vector<content::WebPluginMimeType>::const_iterator type_it =
              it->mime_types.begin();
          type_it != it->mime_types.end();
          ++type_it) {
diff --git a/chrome/browser/automation/testing_automation_provider.h b/chrome/browser/automation/testing_automation_provider.h
index df1fadb..7aad785 100644
--- a/chrome/browser/automation/testing_automation_provider.h
+++ b/chrome/browser/automation/testing_automation_provider.h
@@ -38,16 +38,13 @@
 namespace content {
 class RenderViewHost;
 struct NativeWebKeyboardEvent;
+struct WebPluginInfo;
 }
 
 namespace gfx {
 class Rect;
 }
 
-namespace webkit {
-struct WebPluginInfo;
-}
-
 // This is an automation provider containing testing calls.
 class TestingAutomationProvider : public AutomationProvider,
                                   public chrome::BrowserListObserver,
@@ -402,7 +399,7 @@
   void GetPluginsInfoCallback(Browser* browser,
       base::DictionaryValue* args,
       IPC::Message* reply_message,
-      const std::vector<webkit::WebPluginInfo>& plugins);
+      const std::vector<content::WebPluginInfo>& plugins);
 
   // Enable a plugin.
   // Uses the JSON interface for input/output.
diff --git a/chrome/browser/automation/testing_automation_provider_chromeos.cc b/chrome/browser/automation/testing_automation_provider_chromeos.cc
index a528098..6183395 100644
--- a/chrome/browser/automation/testing_automation_provider_chromeos.cc
+++ b/chrome/browser/automation/testing_automation_provider_chromeos.cc
@@ -38,6 +38,7 @@
 #include "chrome/browser/chromeos/settings/cros_settings.h"
 #include "chrome/browser/chromeos/settings/cros_settings_names.h"
 #include "chrome/browser/chromeos/system/timezone_settings.h"
+#include "chrome/browser/prefs/proxy_config_dictionary.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
diff --git a/chrome/browser/background/background_mode_manager.cc b/chrome/browser/background/background_mode_manager.cc
index 6bbc13b..b925aba 100644
--- a/chrome/browser/background/background_mode_manager.cc
+++ b/chrome/browser/background/background_mode_manager.cc
@@ -665,7 +665,8 @@
   if (!status_tray_ || status_icon_)
     return;
 
-  status_icon_ = status_tray_->CreateStatusIcon();
+  status_icon_ =
+      status_tray_->CreateStatusIcon(StatusTray::BACKGROUND_MODE_ICON);
   if (!status_icon_)
     return;
 
diff --git a/chrome/browser/browser_commands_unittest.cc b/chrome/browser/browser_commands_unittest.cc
index 298b488..7c6ed44 100644
--- a/chrome/browser/browser_commands_unittest.cc
+++ b/chrome/browser/browser_commands_unittest.cc
@@ -167,15 +167,17 @@
   EXPECT_EQ(0, browser()->tab_strip_model()->active_index());
   ASSERT_EQ(2, browser()->tab_strip_model()->count());
 
-  // The original tab should be unchanged.
   WebContents* zeroth = browser()->tab_strip_model()->GetWebContentsAt(0);
-  EXPECT_EQ(url2, zeroth->GetURL());
+  WebContents* first = browser()->tab_strip_model()->GetWebContentsAt(1);
+
+  // The original tab should be unchanged.
+  EXPECT_EQ(url2, zeroth->GetLastCommittedURL());
   EXPECT_TRUE(zeroth->GetController().CanGoBack());
   EXPECT_FALSE(zeroth->GetController().CanGoForward());
 
-  // The new tab should be like the first one but navigated back.
-  WebContents* first = browser()->tab_strip_model()->GetWebContentsAt(1);
-  EXPECT_EQ(url1, browser()->tab_strip_model()->GetWebContentsAt(1)->GetURL());
+  // The new tab should be like the first one but navigated back. Since we
+  // didn't wait for the load to complete, we can't use GetLastCommittedURL.
+  EXPECT_EQ(url1, first->GetVisibleURL());
   EXPECT_FALSE(first->GetController().CanGoBack());
   EXPECT_TRUE(first->GetController().CanGoForward());
 
@@ -190,7 +192,7 @@
   chrome::GoForward(browser(), NEW_BACKGROUND_TAB);
 
   // The previous tab should be unchanged and still in the foreground.
-  EXPECT_EQ(url1, first->GetURL());
+  EXPECT_EQ(url1, first->GetLastCommittedURL());
   EXPECT_FALSE(first->GetController().CanGoBack());
   EXPECT_TRUE(first->GetController().CanGoForward());
   EXPECT_EQ(1, browser()->tab_strip_model()->active_index());
@@ -198,7 +200,9 @@
   // There should be a new tab navigated forward.
   ASSERT_EQ(3, browser()->tab_strip_model()->count());
   WebContents* second = browser()->tab_strip_model()->GetWebContentsAt(2);
-  EXPECT_EQ(url2, second->GetURL());
+  // Since we didn't wait for load to complete, we can't use
+  // GetLastCommittedURL.
+  EXPECT_EQ(url2, second->GetVisibleURL());
   EXPECT_TRUE(second->GetController().CanGoBack());
   EXPECT_FALSE(second->GetController().CanGoForward());
 
@@ -210,7 +214,8 @@
   chrome::GoBack(browser(), NEW_FOREGROUND_TAB);
   ASSERT_EQ(3, browser()->tab_strip_model()->active_index());
   ASSERT_EQ(url1,
-            browser()->tab_strip_model()->GetActiveWebContents()->GetURL());
+            browser()->tab_strip_model()->GetActiveWebContents()->
+                GetVisibleURL());
 
   // Same thing again for forward.
   // TODO(brettw) bug 11055: see the comment above about why we need this.
@@ -219,6 +224,6 @@
   chrome::GoForward(browser(), NEW_FOREGROUND_TAB);
   ASSERT_EQ(4, browser()->tab_strip_model()->active_index());
   ASSERT_EQ(url2,
-            browser()->tab_strip_model()->GetActiveWebContents()->GetURL());
+            browser()->tab_strip_model()->GetActiveWebContents()->
+                GetVisibleURL());
 }
-
diff --git a/chrome/browser/browser_process.h b/chrome/browser/browser_process.h
index 0824b1c..ca828e9 100644
--- a/chrome/browser/browser_process.h
+++ b/chrome/browser/browser_process.h
@@ -47,6 +47,7 @@
 
 namespace chrome {
 class MediaFileSystemRegistry;
+class StorageMonitor;
 }
 
 namespace chrome_variations {
@@ -217,6 +218,8 @@
 
   virtual chrome::MediaFileSystemRegistry* media_file_system_registry() = 0;
 
+  virtual chrome::StorageMonitor* storage_monitor() = 0;
+
   virtual bool created_local_state() const = 0;
 
 #if defined(ENABLE_WEBRTC)
diff --git a/chrome/browser/browser_process_impl.cc b/chrome/browser/browser_process_impl.cc
index 9dffeab..75897f2 100644
--- a/chrome/browser/browser_process_impl.cc
+++ b/chrome/browser/browser_process_impl.cc
@@ -62,6 +62,7 @@
 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
 #include "chrome/browser/shell_integration.h"
 #include "chrome/browser/status_icons/status_tray.h"
+#include "chrome/browser/storage_monitor/storage_monitor.h"
 #include "chrome/browser/thumbnails/render_widget_snapshot_taker.h"
 #include "chrome/browser/ui/bookmarks/bookmark_prompt_controller.h"
 #include "chrome/browser/ui/browser_finder.h"
@@ -106,7 +107,7 @@
 #include "ui/aura/env.h"
 #endif
 
-#if !defined(OS_ANDROID)
+#if !defined(OS_ANDROID) && !defined(OS_IOS)
 #include "chrome/browser/media_galleries/media_file_system_registry.h"
 #endif
 
@@ -251,6 +252,15 @@
 
   ExtensionRendererState::GetInstance()->Shutdown();
 
+#if !defined(OS_ANDROID) && !defined(OS_IOS)
+  media_file_system_registry_.reset();
+  // Delete |storage_monitor_| now. Otherwise the FILE thread would be gone
+  // when we try to release it in the dtor and Valgrind would report a
+  // leak on almost every single browser_test.
+  // TODO(gbillock): Make this unnecessary.
+  storage_monitor_.reset();
+#endif
+
   message_center::MessageCenter::Shutdown();
 
 #if defined(ENABLE_CONFIGURATION_POLICY)
@@ -619,9 +629,24 @@
 #endif
 }
 
+chrome::StorageMonitor* BrowserProcessImpl::storage_monitor() {
+#if defined(OS_ANDROID) || defined(OS_IOS)
+  return NULL;
+#else
+  return storage_monitor_.get();
+#endif
+}
+
+void BrowserProcessImpl::set_storage_monitor_for_test(
+    scoped_ptr<chrome::StorageMonitor> monitor) {
+#if !defined(OS_ANDROID) && !defined(OS_IOS)
+  storage_monitor_ = monitor.Pass();
+#endif
+}
+
 chrome::MediaFileSystemRegistry*
 BrowserProcessImpl::media_file_system_registry() {
-#if defined(OS_ANDROID)
+#if defined(OS_ANDROID) || defined(OS_IOS)
     return NULL;
 #else
   if (!media_file_system_registry_)
@@ -910,6 +935,10 @@
   }
 #endif
 
+#if !defined(OS_ANDROID) && !defined(OS_IOS)
+  storage_monitor_.reset(chrome::StorageMonitor::Create());
+#endif
+
 #if defined(OS_MACOSX)
   app_shim_host_manager_.reset(new AppShimHostManager);
   AppListService::InitAll(NULL);
diff --git a/chrome/browser/browser_process_impl.h b/chrome/browser/browser_process_impl.h
index 66191dc..50a76d1 100644
--- a/chrome/browser/browser_process_impl.h
+++ b/chrome/browser/browser_process_impl.h
@@ -127,6 +127,8 @@
   virtual CRLSetFetcher* crl_set_fetcher() OVERRIDE;
   virtual PnaclComponentInstaller* pnacl_component_installer() OVERRIDE;
   virtual BookmarkPromptController* bookmark_prompt_controller() OVERRIDE;
+  virtual chrome::StorageMonitor* storage_monitor() OVERRIDE;
+  void set_storage_monitor_for_test(scoped_ptr<chrome::StorageMonitor> monitor);
   virtual chrome::MediaFileSystemRegistry*
       media_file_system_registry() OVERRIDE;
   virtual bool created_local_state() const OVERRIDE;
@@ -196,6 +198,10 @@
 
   // Bookmark prompt controller displays the prompt for frequently visited URL.
   scoped_ptr<BookmarkPromptController> bookmark_prompt_controller_;
+#endif
+
+#if !defined(OS_ANDROID) && !defined(OS_IOS)
+  scoped_ptr<chrome::StorageMonitor> storage_monitor_;
 
   scoped_ptr<chrome::MediaFileSystemRegistry> media_file_system_registry_;
 #endif
diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd
index 2234ae0..cc669ab 100644
--- a/chrome/browser/browser_resources.grd
+++ b/chrome/browser/browser_resources.grd
@@ -161,12 +161,6 @@
       <include name="IDR_LOCAL_NTP_JS" file="resources\local_ntp\local_ntp.js" flattenhtml="true" 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_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" />
-      <include name="IDR_LOCAL_OMNIBOX_POPUP_IMAGES_PAGE_ICON_PNG" file="resources\local_omnibox_popup\images\page_icon.png" type="BINDATA" />
-      <include name="IDR_LOCAL_OMNIBOX_POPUP_IMAGES_2X_PAGE_ICON_PNG" file="resources\local_omnibox_popup\images\2x\page_icon.png" type="BINDATA" />
-      <include name="IDR_LOCAL_OMNIBOX_POPUP_IMAGES_SEARCH_ICON_PNG" file="resources\local_omnibox_popup\images\search_icon.png" type="BINDATA" />
-      <include name="IDR_LOCAL_OMNIBOX_POPUP_IMAGES_2X_SEARCH_ICON_PNG" file="resources\local_omnibox_popup\images\2x\search_icon.png" type="BINDATA" />
       <include name="IDR_MOST_VISITED_IFRAME_CSS" file="resources\local_ntp\most_visited_iframe.css" type="BINDATA" />
       <include name="IDR_MOST_VISITED_TITLE_HTML" file="resources\local_ntp\most_visited_title.html" type="BINDATA" />
       <include name="IDR_MOST_VISITED_TITLE_CSS" file="resources\local_ntp\most_visited_title.css" type="BINDATA" />
@@ -288,6 +282,8 @@
         <include name="IDR_CRYPTOHOME_JS" file="resources\chromeos\cryptohome.js" type="BINDATA" />
         <!-- manifest file of ChromeVox accessibility extension -->
         <include name="IDR_CHROMEVOX_MANIFEST" file="resources\chromeos\access_chromevox\manifest.json" type="BINDATA" />
+        <!-- manifest file of Connectivity Diagnostics app -->
+        <include name="IDR_CONNECTIVITY_DIAGNOSTICS_MANIFEST" file="resources\chromeos\connectivity_diagnostics\manifest.json" type="BINDATA" />
         <!-- manifest file of built-in speech synthesis extension -->
         <include name="IDR_SPEECH_SYNTHESIS_MANIFEST" file="resources\chromeos\speech_synthesis\manifest.json" type="BINDATA" />
         <include name="IDR_DIAGNOSTICS_MAIN_CSS" file="resources\chromeos\diagnostics\main.css" type="BINDATA" />
@@ -358,11 +354,14 @@
         <include name="IDR_SET_AS_DEFAULT_BROWSER_JS" file="resources\set_as_default_browser.js" flattenhtml="true" type="BINDATA" />
         <include name="IDR_SET_AS_DEFAULT_BROWSER_HTML" file="resources\set_as_default_browser.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
       </if>
+      <if expr="not is_android and not pp_ifdef('ios') and not pp_ifdef('chromeos')">
+        <include name="IDR_USER_CHOOSER_JS" file="resources\user_chooser\user_chooser.js" flattenhtml="true" type="BINDATA" />
+        <include name="IDR_USER_CHOOSER_HTML" file="resources\user_chooser\user_chooser.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
+      </if>
       <include name="IDR_MANAGED_MODE_BLOCK_INTERSTITIAL_HTML" file="resources\managed_mode_block_interstitial.html" flattenhtml="true" type="BINDATA" />
       <include name="IDR_PROFILE_SIGNIN_CONFIRMATION_HTML" file="resources\profile_signin_confirmation.html" type="BINDATA" />
       <include name="IDR_PROFILE_SIGNIN_CONFIRMATION_JS" file="resources\profile_signin_confirmation.js" type="BINDATA" />
       <include name="IDR_PROFILE_SIGNIN_CONFIRMATION_CSS" file="resources\profile_signin_confirmation.css" type="BINDATA" />
-
       <include name="IDR_RECENTLY_CLOSED_WINDOW" file="resources\ntp4\images\closed_window.png" type="BINDATA" />
       <if expr="not is_android">
         <include name="IDR_IDENTITY_INTERNALS_HTML" file="resources\identity_internals.html" type="BINDATA" />
diff --git a/chrome/browser/browsing_data/browsing_data_database_helper.cc b/chrome/browser/browsing_data/browsing_data_database_helper.cc
index 023dfff..5cd0fb5 100644
--- a/chrome/browser/browsing_data/browsing_data_database_helper.cc
+++ b/chrome/browser/browsing_data/browsing_data_database_helper.cc
@@ -15,8 +15,6 @@
 #include "content/public/browser/storage_partition.h"
 #include "net/base/completion_callback.h"
 #include "net/base/net_errors.h"
-#include "third_party/WebKit/public/platform/WebCString.h"
-#include "third_party/WebKit/public/platform/WebString.h"
 #include "webkit/common/database/database_identifier.h"
 
 using content::BrowserContext;
diff --git a/chrome/browser/browsing_data/browsing_data_helper.cc b/chrome/browser/browsing_data/browsing_data_helper.cc
index 0faf856..73239b7 100644
--- a/chrome/browser/browsing_data/browsing_data_helper.cc
+++ b/chrome/browser/browsing_data/browsing_data_helper.cc
@@ -11,7 +11,6 @@
 #include "chrome/common/url_constants.h"
 #include "content/public/browser/child_process_security_policy.h"
 #include "extensions/common/constants.h"
-#include "third_party/WebKit/public/platform/WebString.h"
 #include "url/gurl.h"
 
 // Static
@@ -34,11 +33,6 @@
 }
 
 // Static
-bool BrowsingDataHelper::IsWebScheme(const WebKit::WebString& scheme) {
-  return BrowsingDataHelper::IsWebScheme(UTF16ToUTF8(scheme));
-}
-
-// Static
 bool BrowsingDataHelper::HasWebScheme(const GURL& origin) {
   return BrowsingDataHelper::IsWebScheme(origin.scheme());
 }
@@ -49,11 +43,6 @@
 }
 
 // Static
-bool BrowsingDataHelper::IsExtensionScheme(const WebKit::WebString& scheme) {
-  return BrowsingDataHelper::IsExtensionScheme(UTF16ToUTF8(scheme));
-}
-
-// Static
 bool BrowsingDataHelper::HasExtensionScheme(const GURL& origin) {
   return BrowsingDataHelper::IsExtensionScheme(origin.scheme());
 }
diff --git a/chrome/browser/browsing_data/browsing_data_helper.h b/chrome/browser/browsing_data/browsing_data_helper.h
index 65afbcc..1afacdb 100644
--- a/chrome/browser/browsing_data/browsing_data_helper.h
+++ b/chrome/browser/browsing_data/browsing_data_helper.h
@@ -11,10 +11,6 @@
 
 #include "base/basictypes.h"
 
-namespace WebKit {
-class WebString;
-}
-
 class ExtensionSpecialStoragePolicy;
 class GURL;
 
@@ -33,12 +29,10 @@
   // in ChildProcessSecurityPolicy, but excluding schemes like
   // `chrome-extension`.
   static bool IsWebScheme(const std::string& scheme);
-  static bool IsWebScheme(const WebKit::WebString& scheme);
   static bool HasWebScheme(const GURL& origin);
 
   // Returns true iff the provided scheme is an extension.
   static bool IsExtensionScheme(const std::string& scheme);
-  static bool IsExtensionScheme(const WebKit::WebString& scheme);
   static bool HasExtensionScheme(const GURL& origin);
 
   // Returns true if the provided origin matches the provided mask.
diff --git a/chrome/browser/browsing_data/browsing_data_helper_unittest.cc b/chrome/browser/browsing_data/browsing_data_helper_unittest.cc
index e19b81a..4901f64 100644
--- a/chrome/browser/browsing_data/browsing_data_helper_unittest.cc
+++ b/chrome/browser/browsing_data/browsing_data_helper_unittest.cc
@@ -10,7 +10,6 @@
 #include "content/public/common/url_constants.h"
 #include "extensions/common/constants.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/WebKit/public/platform/WebString.h"
 #include "url/gurl.h"
 
 namespace {
@@ -39,17 +38,13 @@
   bool IsWebScheme(const std::string& scheme) {
     GURL test(scheme + "://example.com");
     return (BrowsingDataHelper::HasWebScheme(test) &&
-            BrowsingDataHelper::IsWebScheme(scheme) &&
-            BrowsingDataHelper::IsWebScheme(
-                WebKit::WebString::fromUTF8(scheme)));
+            BrowsingDataHelper::IsWebScheme(scheme));
   }
 
   bool IsExtensionScheme(const std::string& scheme) {
     GURL test(scheme + "://example.com");
     return (BrowsingDataHelper::HasExtensionScheme(test) &&
-            BrowsingDataHelper::IsExtensionScheme(scheme) &&
-            BrowsingDataHelper::IsExtensionScheme(
-                WebKit::WebString::fromUTF8(scheme)));
+            BrowsingDataHelper::IsExtensionScheme(scheme));
   }
 
   bool Match(const GURL& origin,
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 18840f7..1252aa4 100644
--- a/chrome/browser/browsing_data/browsing_data_indexed_db_helper.cc
+++ b/chrome/browser/browsing_data/browsing_data_indexed_db_helper.cc
@@ -224,7 +224,8 @@
   for (std::set<PendingIndexedDBInfo>::const_iterator
        pending_info = pending_indexed_db_info_.begin();
        pending_info != pending_indexed_db_info_.end(); ++pending_info) {
-    IndexedDBInfo info(pending_info->origin, 0, base::Time(), base::FilePath());
+    IndexedDBInfo info(
+        pending_info->origin, 0, base::Time(), base::FilePath(), 0);
     indexed_db_info_.push_back(info);
   }
 
diff --git a/chrome/browser/browsing_data/browsing_data_remover_unittest.cc b/chrome/browser/browsing_data/browsing_data_remover_unittest.cc
index 03b176a..3d659ce 100644
--- a/chrome/browser/browsing_data/browsing_data_remover_unittest.cc
+++ b/chrome/browser/browsing_data/browsing_data_remover_unittest.cc
@@ -43,8 +43,6 @@
 #include "net/url_request/url_request_context.h"
 #include "net/url_request/url_request_context_getter.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/WebKit/public/platform/WebCString.h"
-#include "third_party/WebKit/public/platform/WebString.h"
 #include "webkit/browser/quota/mock_quota_manager.h"
 #include "webkit/browser/quota/quota_manager.h"
 #include "webkit/common/dom_storage/dom_storage_types.h"
diff --git a/chrome/browser/browsing_data/mock_browsing_data_indexed_db_helper.cc b/chrome/browser/browsing_data/mock_browsing_data_indexed_db_helper.cc
index 5d9d4d9..c933bb9 100644
--- a/chrome/browser/browsing_data/mock_browsing_data_indexed_db_helper.cc
+++ b/chrome/browser/browsing_data/mock_browsing_data_indexed_db_helper.cc
@@ -28,10 +28,10 @@
 void MockBrowsingDataIndexedDBHelper::AddIndexedDBSamples() {
   const GURL kOrigin1("http://idbhost1:1/");
   const GURL kOrigin2("http://idbhost2:2/");
-  content::IndexedDBInfo info1(kOrigin1, 1, base::Time(), base::FilePath());
+  content::IndexedDBInfo info1(kOrigin1, 1, base::Time(), base::FilePath(), 0);
   response_.push_back(info1);
   origins_[kOrigin1] = true;
-  content::IndexedDBInfo info2(kOrigin2, 2, base::Time(), base::FilePath());
+  content::IndexedDBInfo info2(kOrigin2, 2, base::Time(), base::FilePath(), 0);
   response_.push_back(info2);
   origins_[kOrigin2] = true;
 }
diff --git a/chrome/browser/captive_portal/captive_portal_tab_helper.h b/chrome/browser/captive_portal/captive_portal_tab_helper.h
index 88cf5ef..dec16d2 100644
--- a/chrome/browser/captive_portal/captive_portal_tab_helper.h
+++ b/chrome/browser/captive_portal/captive_portal_tab_helper.h
@@ -14,7 +14,7 @@
 #include "content/public/browser/notification_registrar.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/browser/web_contents_user_data.h"
-#include "webkit/glue/resource_type.h"
+#include "webkit/common/resource_type.h"
 
 class GURL;
 class Profile;
diff --git a/chrome/browser/character_encoding.cc b/chrome/browser/character_encoding.cc
index 9a0f112..4909a7b 100644
--- a/chrome/browser/character_encoding.cc
+++ b/chrome/browser/character_encoding.cc
@@ -15,7 +15,7 @@
 #include "chrome/app/chrome_command_ids.h"
 #include "content/public/browser/browser_thread.h"
 #include "grit/generated_resources.h"
-#include "third_party/icu/public/common/unicode/ucnv.h"
+#include "third_party/icu/source/common/unicode/ucnv.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/l10n/l10n_util_collator.h"
 
diff --git a/chrome/browser/chrome_browser_field_trials_mobile.cc b/chrome/browser/chrome_browser_field_trials_mobile.cc
index 7fb1896..5e17ca7 100644
--- a/chrome/browser/chrome_browser_field_trials_mobile.cc
+++ b/chrome/browser/chrome_browser_field_trials_mobile.cc
@@ -9,6 +9,7 @@
 #include "base/command_line.h"
 #include "base/metrics/field_trial.h"
 #include "base/prefs/pref_service.h"
+#include "chrome/common/chrome_switches.h"
 #include "chrome/common/chrome_version_info.h"
 
 namespace chrome {
@@ -51,12 +52,55 @@
           << ". Selected group id: " << v;
 }
 
+void NewTabButtonInToolbarFieldTrial(const CommandLine& parsed_command_line) {
+  // Do not enable this field trials for tablet devices.
+  if (parsed_command_line.HasSwitch(switches::kTabletUI))
+    return;
+
+  const char kPhoneNewTabToolbarButtonFieldTrialName[] =
+      "PhoneNewTabToolbarButton";
+  const base::FieldTrial::Probability kPhoneNewTabToolbarButtonDivisor = 100;
+
+  // 50/100 = 50% for Non-Stable users.
+  //  0/100 = 0%  for Stable users.
+  const base::FieldTrial::Probability kPhoneNewTabToolbarButtonNonStable = 50;
+  const base::FieldTrial::Probability kPhoneNewTabToolbarButtonStable = 0;
+  const char kEnabled[] = "Enabled";
+  const char kDisabled[] = "Disabled";
+
+  // Find out if this is a stable channel.
+  const bool kIsStableChannel =
+      chrome::VersionInfo::GetChannel() == chrome::VersionInfo::CHANNEL_STABLE;
+
+  // Experiment enabled until Jan 1, 2015. By default, disabled.
+  scoped_refptr<base::FieldTrial> trial(
+      base::FieldTrialList::FactoryGetFieldTrial(
+          kPhoneNewTabToolbarButtonFieldTrialName,
+          kPhoneNewTabToolbarButtonDivisor,
+          kDisabled, 2015, 1, 1, NULL));
+
+  // We want our trial results to be persistent.
+  trial->UseOneTimeRandomization();
+  const int kEnabledGroup = trial->AppendGroup(
+      kEnabled,
+      kIsStableChannel ?
+          kPhoneNewTabToolbarButtonStable : kPhoneNewTabToolbarButtonNonStable);
+
+  const int v = trial->group();
+  VLOG(1) << "Phone NewTab toolbar button enabled group id: " << kEnabledGroup
+          << ". Selected group id: " << v;
+}
+
 }  // namespace
 
 void SetupMobileFieldTrials(const CommandLine& parsed_command_line,
                             const base::Time& install_time,
                             PrefService* local_state) {
   DataCompressionProxyFieldTrial();
+
+#if defined(OS_ANDROID)
+  NewTabButtonInToolbarFieldTrial(parsed_command_line);
+#endif
 }
 
 }  // namespace chrome
diff --git a/chrome/browser/chrome_browser_main.cc b/chrome/browser/chrome_browser_main.cc
index bcc7b11..b8e5204 100644
--- a/chrome/browser/chrome_browser_main.cc
+++ b/chrome/browser/chrome_browser_main.cc
@@ -1019,6 +1019,8 @@
             prefs::kBrowserSuppressDefaultBrowserPrompt,
             master_prefs_->suppress_default_browser_prompt_for_version);
       }
+
+      AppListService::Get()->HandleFirstRun();
     }
 
     if (do_first_run_tasks_ ||
diff --git a/chrome/browser/chrome_browser_main_linux.cc b/chrome/browser/chrome_browser_main_linux.cc
index dd83909..299154d 100644
--- a/chrome/browser/chrome_browser_main_linux.cc
+++ b/chrome/browser/chrome_browser_main_linux.cc
@@ -118,11 +118,6 @@
   if (IsCrashReportingEnabled(local_state()))
     InitCrashReporter();
 
-#if !defined(OS_CHROMEOS)
-  const base::FilePath kDefaultMtabPath("/etc/mtab");
-  storage_monitor_.reset(new chrome::StorageMonitorLinux(kDefaultMtabPath));
-#endif
-
   ChromeBrowserMainPartsPosix::PreProfileInit();
 }
 
@@ -132,14 +127,3 @@
   g_browser_process->metrics_service()->RecordBreakpadRegistration(
       IsCrashReporterEnabled());
 }
-
-void ChromeBrowserMainPartsLinux::PostMainMessageLoopRun() {
-  ChromeBrowserMainPartsPosix::PostMainMessageLoopRun();
-
-#if !defined(OS_CHROMEOS)
-  // Delete it now. Otherwise the FILE thread would be gone when we try to
-  // release it in the dtor and Valgrind would report a leak on almost every
-  // single browser_test.
-  storage_monitor_.reset();
-#endif
-}
diff --git a/chrome/browser/chrome_browser_main_linux.h b/chrome/browser/chrome_browser_main_linux.h
index 3cc5476..37f35ce 100644
--- a/chrome/browser/chrome_browser_main_linux.h
+++ b/chrome/browser/chrome_browser_main_linux.h
@@ -8,15 +8,8 @@
 #define CHROME_BROWSER_CHROME_BROWSER_MAIN_LINUX_H_
 
 #include "base/compiler_specific.h"
-#include "base/memory/scoped_ptr.h"
 #include "chrome/browser/chrome_browser_main_posix.h"
 
-#if !defined(OS_CHROMEOS)
-namespace chrome {
-class StorageMonitorLinux;
-}
-#endif
-
 class ChromeBrowserMainPartsLinux : public ChromeBrowserMainPartsPosix {
  public:
   explicit ChromeBrowserMainPartsLinux(
@@ -26,13 +19,8 @@
   // ChromeBrowserMainParts overrides.
   virtual void PreProfileInit() OVERRIDE;
   virtual void PostProfileInit() OVERRIDE;
-  virtual void PostMainMessageLoopRun() OVERRIDE;
 
  private:
-#if !defined(OS_CHROMEOS)
-  scoped_ptr<chrome::StorageMonitorLinux> storage_monitor_;
-#endif
-
   DISALLOW_COPY_AND_ASSIGN(ChromeBrowserMainPartsLinux);
 };
 
diff --git a/chrome/browser/chrome_browser_main_mac.h b/chrome/browser/chrome_browser_main_mac.h
index 52f6cf1..efe1bc7 100644
--- a/chrome/browser/chrome_browser_main_mac.h
+++ b/chrome/browser/chrome_browser_main_mac.h
@@ -5,13 +5,8 @@
 #ifndef CHROME_BROWSER_CHROME_BROWSER_MAIN_MAC_H_
 #define CHROME_BROWSER_CHROME_BROWSER_MAIN_MAC_H_
 
-#include "base/memory/scoped_ptr.h"
 #include "chrome/browser/chrome_browser_main_posix.h"
 
-namespace chrome {
-class StorageMonitorMac;
-}
-
 class ChromeBrowserMainPartsMac : public ChromeBrowserMainPartsPosix {
  public:
   explicit ChromeBrowserMainPartsMac(
@@ -21,7 +16,6 @@
   // BrowserParts overrides.
   virtual void PreEarlyInitialization() OVERRIDE;
   virtual void PreMainMessageLoopStart() OVERRIDE;
-  virtual void PreProfileInit() OVERRIDE;
   virtual void PostProfileInit() OVERRIDE;
 
   // Perform platform-specific work that needs to be done after the main event
@@ -29,8 +23,6 @@
   static void DidEndMainMessageLoop();
 
  private:
-  scoped_ptr<chrome::StorageMonitorMac> storage_monitor_;
-
   DISALLOW_COPY_AND_ASSIGN(ChromeBrowserMainPartsMac);
 };
 
diff --git a/chrome/browser/chrome_browser_main_mac.mm b/chrome/browser/chrome_browser_main_mac.mm
index af5ee81..3d41c65 100644
--- a/chrome/browser/chrome_browser_main_mac.mm
+++ b/chrome/browser/chrome_browser_main_mac.mm
@@ -22,7 +22,6 @@
 #include "chrome/browser/mac/keychain_reauthorize.h"
 #import "chrome/browser/mac/keystone_glue.h"
 #include "chrome/browser/metrics/metrics_service.h"
-#include "chrome/browser/storage_monitor/storage_monitor_mac.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/chrome_switches.h"
 #include "content/public/common/main_function_params.h"
@@ -265,12 +264,6 @@
       setObject:@"NO" forKey:@"NSTreatUnknownArgumentsAsOpen"];
 }
 
-void ChromeBrowserMainPartsMac::PreProfileInit() {
-  storage_monitor_.reset(new chrome::StorageMonitorMac());
-
-  ChromeBrowserMainPartsPosix::PreProfileInit();
-}
-
 void ChromeBrowserMainPartsMac::PostProfileInit() {
   ChromeBrowserMainPartsPosix::PostProfileInit();
   g_browser_process->metrics_service()->RecordBreakpadRegistration(
diff --git a/chrome/browser/chrome_browser_main_win.cc b/chrome/browser/chrome_browser_main_win.cc
index 66c615a..a2e3008 100644
--- a/chrome/browser/chrome_browser_main_win.cc
+++ b/chrome/browser/chrome_browser_main_win.cc
@@ -27,7 +27,6 @@
 #include "chrome/browser/profiles/profile_info_cache.h"
 #include "chrome/browser/profiles/profile_shortcut_manager.h"
 #include "chrome/browser/shell_integration.h"
-#include "chrome/browser/storage_monitor/storage_monitor_win.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"
@@ -212,7 +211,7 @@
 void ChromeBrowserMainPartsWin::PostMainMessageLoopRun() {
   // Log the search engine chosen on first run. Do this at shutdown, after any
   // changes are made from the first run bubble link, etc.
-  if (do_first_run_tasks() && !profile()->IsOffTheRecord()) {
+  if (do_first_run_tasks() && profile() && !profile()->IsOffTheRecord()) {
     TemplateURLService* url_service =
         TemplateURLServiceFactory::GetForProfile(profile());
     const TemplateURL* default_search_engine =
@@ -230,12 +229,6 @@
   ChromeBrowserMainParts::PostMainMessageLoopRun();
 }
 
-void ChromeBrowserMainPartsWin::PreProfileInit() {
-  storage_monitor_.reset(chrome::StorageMonitorWin::Create());
-
-  ChromeBrowserMainParts::PreProfileInit();
-}
-
 void ChromeBrowserMainPartsWin::ShowMissingLocaleMessageBox() {
   ui::MessageBox(NULL, ASCIIToUTF16(chrome_browser::kMissingLocaleDataMessage),
                  ASCIIToUTF16(chrome_browser::kMissingLocaleDataTitle),
diff --git a/chrome/browser/chrome_browser_main_win.h b/chrome/browser/chrome_browser_main_win.h
index 6da509e..496d234 100644
--- a/chrome/browser/chrome_browser_main_win.h
+++ b/chrome/browser/chrome_browser_main_win.h
@@ -7,16 +7,10 @@
 #ifndef CHROME_BROWSER_CHROME_BROWSER_MAIN_WIN_H_
 #define CHROME_BROWSER_CHROME_BROWSER_MAIN_WIN_H_
 
-#include "base/memory/scoped_ptr.h"
 #include "chrome/browser/chrome_browser_main.h"
 
 class CommandLine;
 
-namespace chrome {
-class StorageMonitorWin;
-}  // namespace chrome
-
-
 // Handle uninstallation when given the appropriate the command-line switch.
 // If |chrome_still_running| is true a modal dialog will be shown asking the
 // user to close the other chrome instance.
@@ -34,7 +28,6 @@
   virtual void PreMainMessageLoopStart() OVERRIDE;
   virtual int PreCreateThreads() OVERRIDE;
   virtual void PostMainMessageLoopRun() OVERRIDE;
-  virtual void PreProfileInit() OVERRIDE;
 
   // ChromeBrowserMainParts overrides.
   virtual void ShowMissingLocaleMessageBox() OVERRIDE;
@@ -68,8 +61,6 @@
   static void SetupInstallerUtilStrings();
 
  private:
-  scoped_ptr<chrome::StorageMonitorWin> storage_monitor_;
-
   DISALLOW_COPY_AND_ASSIGN(ChromeBrowserMainPartsWin);
 };
 
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index ba3f684..8aa4767 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -125,6 +125,7 @@
 #include "content/public/common/content_descriptors.h"
 #include "extensions/browser/view_type_utils.h"
 #include "extensions/common/constants.h"
+#include "extensions/common/switches.h"
 #include "grit/generated_resources.h"
 #include "grit/ui_resources.h"
 #include "net/base/escape.h"
@@ -687,8 +688,8 @@
       ExtensionService* extension_service =
           extensions::ExtensionSystem::Get(profile)->extension_service();
       if (extension_service) {
-        extension = extension_service->extensions()->
-            GetExtensionOrAppByURL(ExtensionURLInfo(site));
+        extension =
+            extension_service->extensions()->GetExtensionOrAppByURL(site);
         if (extension &&
             extensions::AppIsolationInfo::HasIsolatedStorage(extension)) {
           is_isolated = true;
@@ -785,8 +786,8 @@
     return;
   }
   const GURL& url = embedder_web_contents->GetSiteInstance()->GetSiteURL();
-  const Extension* extension = service->extensions()->
-      GetExtensionOrAppByURL(ExtensionURLInfo(url));
+  const Extension* extension =
+      service->extensions()->GetExtensionOrAppByURL(url);
   if (!extension) {
     NOTREACHED();
     return;
@@ -909,7 +910,7 @@
     return url;
 
   const Extension* extension = extension_service->extensions()->
-      GetHostedAppByURL(ExtensionURLInfo(url));
+      GetHostedAppByURL(url);
   if (!extension)
     return url;
 
@@ -950,8 +951,8 @@
   if (!extension_service)
     return false;
 
-  const Extension* extension = extension_service->extensions()->
-      GetExtensionOrAppByURL(ExtensionURLInfo(effective_url));
+  const Extension* extension =
+      extension_service->extensions()->GetExtensionOrAppByURL(effective_url);
   if (!extension)
     return false;
 
@@ -1016,7 +1017,7 @@
   if (!service)
     return true;
   const Extension* new_extension =
-      service->extensions()->GetExtensionOrAppByURL(ExtensionURLInfo(url));
+      service->extensions()->GetExtensionOrAppByURL(url);
   if (new_extension &&
       new_extension->is_hosted_app() &&
       new_extension->id() == extension_misc::kWebStoreAppId &&
@@ -1100,7 +1101,7 @@
 
   // We have to have a valid extension with background page to proceed.
   const Extension* extension =
-      service->extensions()->GetExtensionOrAppByURL(ExtensionURLInfo(url));
+      service->extensions()->GetExtensionOrAppByURL(url);
   if (!extension)
     return false;
   if (!extensions::BackgroundInfo::HasBackgroundPage(extension))
@@ -1175,9 +1176,8 @@
   if (!service)
     return;
 
-  const Extension* extension =
-      service->extensions()->GetExtensionOrAppByURL(ExtensionURLInfo(
-          site_instance->GetSiteURL()));
+  const Extension* extension = service->extensions()->GetExtensionOrAppByURL(
+      site_instance->GetSiteURL());
   if (!extension)
     return;
 
@@ -1205,9 +1205,8 @@
   if (!service)
     return;
 
-  const Extension* extension =
-      service->extensions()->GetExtensionOrAppByURL(
-          ExtensionURLInfo(site_instance->GetSiteURL()));
+  const Extension* extension = service->extensions()->GetExtensionOrAppByURL(
+      site_instance->GetSiteURL());
   if (!extension)
     return;
 
@@ -1257,7 +1256,7 @@
   // We must swap if the URL is for an extension and we are not using an
   // extension process.
   const Extension* new_extension =
-      service->extensions()->GetExtensionOrAppByURL(ExtensionURLInfo(new_url));
+      service->extensions()->GetExtensionOrAppByURL(new_url);
   // Ignore all hosted apps except the Chrome Web Store, since they do not
   // require their own BrowsingInstance (e.g., postMessage is ok).
   if (new_extension &&
@@ -1279,7 +1278,7 @@
   ProfileIOData* io_data = ProfileIOData::FromResourceContext(resource_context);
   return extensions::CrossesExtensionProcessBoundary(
       io_data->GetExtensionInfoMap()->extensions(),
-      ExtensionURLInfo(current_url), ExtensionURLInfo(new_url), false);
+      current_url, new_url, false);
 }
 
 bool ChromeContentBrowserClient::ShouldAssignSiteForURL(const GURL& url) {
@@ -1387,12 +1386,13 @@
       autofill::switches::kDisableInteractiveAutocomplete,
       autofill::switches::kEnableExperimentalFormFilling,
       autofill::switches::kEnableInteractiveAutocomplete,
+      extensions::switches::kAllowLegacyExtensionManifests,
+      extensions::switches::kAllowScriptingGallery,
+      extensions::switches::kExtensionsOnChromeURLs,
       switches::kAllowHTTPBackgroundPage,
-      switches::kAllowLegacyExtensionManifests,
       // TODO(victorhsieh): remove the following flag once we move PPAPI FileIO
       // to browser.
       switches::kAllowNaClFileHandleAPI,
-      switches::kAllowScriptingGallery,
       switches::kAppsCheckoutURL,
       switches::kAppsGalleryURL,
       switches::kCloudPrintServiceURL,
@@ -1411,7 +1411,6 @@
       switches::kEnablePasswordGeneration,
       switches::kEnablePnacl,
       switches::kEnableWatchdog,
-      switches::kExtensionsOnChromeURLs,
       switches::kMemoryProfiling,
       switches::kMessageLoopHistogrammer,
       switches::kNoJsRandomness,
@@ -1433,9 +1432,9 @@
                                    arraysize(kSwitchNames));
   } else if (process_type == switches::kUtilityProcess) {
     static const char* const kSwitchNames[] = {
+      extensions::switches::kExtensionsOnChromeURLs,
       switches::kAllowHTTPBackgroundPage,
       switches::kEnableExperimentalExtensionApis,
-      switches::kExtensionsOnChromeURLs,
       switches::kWhitelistedExtensionID,
     };
 
@@ -1939,8 +1938,8 @@
     // because the permission check above would have caused an early return
     // already. We must use the full URL to find hosted apps, though, and not
     // just the origin.
-    const Extension* extension = map->extensions().GetExtensionOrAppByURL(
-        ExtensionURLInfo(opener_url));
+    const Extension* extension =
+        map->extensions().GetExtensionOrAppByURL(opener_url);
     if (extension && !extensions::BackgroundInfo::AllowJSAccess(extension))
       *no_javascript_access = true;
   }
@@ -2265,8 +2264,8 @@
   if (!service)
     return false;
 
-  const Extension* extension = service->extensions()->
-      GetExtensionOrAppByURL(ExtensionURLInfo(site_url));
+  const Extension* extension =
+      service->extensions()->GetExtensionOrAppByURL(site_url);
   if (!extension)
     return false;
 
diff --git a/chrome/browser/chrome_main_browsertest.cc b/chrome/browser/chrome_main_browsertest.cc
index 12ee266..d1fc436 100644
--- a/chrome/browser/chrome_main_browsertest.cc
+++ b/chrome/browser/chrome_main_browsertest.cc
@@ -22,6 +22,10 @@
 #include "content/public/browser/web_contents.h"
 #include "net/base/net_util.h"
 
+#if defined(OS_WIN) && defined(USE_ASH)
+#include "base/win/windows_version.h"
+#endif
+
 // These tests don't apply to the Mac version; see GetCommandLineForRelaunch
 // for details.
 #if !defined(OS_MACOSX)
@@ -37,6 +41,12 @@
 
 // Make sure that the second invocation creates a new window.
 IN_PROC_BROWSER_TEST_F(ChromeMainTest, SecondLaunch) {
+#if defined(OS_WIN) && defined(USE_ASH)
+  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
+  if (base::win::GetVersion() >= base::win::VERSION_WIN8)
+    return;
+#endif
+
   ui_test_utils::BrowserAddedObserver observer;
   Relaunch(GetCommandLineForRelaunch());
   observer.WaitForSingleNewBrowser();
@@ -45,6 +55,12 @@
 }
 
 IN_PROC_BROWSER_TEST_F(ChromeMainTest, ReuseBrowserInstanceWhenOpeningFile) {
+#if defined(OS_WIN) && defined(USE_ASH)
+  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
+  if (base::win::GetVersion() >= base::win::VERSION_WIN8)
+    return;
+#endif
+
   base::FilePath test_file_path = ui_test_utils::GetTestFilePath(
       base::FilePath(), base::FilePath().AppendASCII("empty.html"));
   CommandLine new_command_line(GetCommandLineForRelaunch());
@@ -94,6 +110,12 @@
 }
 
 IN_PROC_BROWSER_TEST_F(ChromeMainTest, SecondLaunchFromIncognitoWithNormalUrl) {
+#if defined(OS_WIN) && defined(USE_ASH)
+  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
+  if (base::win::GetVersion() >= base::win::VERSION_WIN8)
+    return;
+#endif
+
   // We should start with one normal window.
   ASSERT_EQ(1u, chrome::GetTabbedBrowserCount(browser()->profile(),
                                               browser()->host_desktop_type()));
diff --git a/chrome/browser/chrome_plugin_browsertest.cc b/chrome/browser/chrome_plugin_browsertest.cc
index d7b76b0..6b2bcba 100644
--- a/chrome/browser/chrome_plugin_browsertest.cc
+++ b/chrome/browser/chrome_plugin_browsertest.cc
@@ -23,11 +23,11 @@
 #include "content/public/browser/plugin_service.h"
 #include "content/public/common/content_paths.h"
 #include "content/public/common/process_type.h"
+#include "content/public/common/webplugininfo.h"
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/test_utils.h"
 #include "net/base/net_util.h"
 #include "webkit/plugins/plugin_constants.h"
-#include "webkit/plugins/webplugininfo.h"
 
 using content::BrowserThread;
 
@@ -106,16 +106,16 @@
 
   static void GetFlashPath(std::vector<base::FilePath>* paths) {
     paths->clear();
-    std::vector<webkit::WebPluginInfo> plugins = GetPlugins();
-    for (std::vector<webkit::WebPluginInfo>::const_iterator it =
+    std::vector<content::WebPluginInfo> plugins = GetPlugins();
+    for (std::vector<content::WebPluginInfo>::const_iterator it =
              plugins.begin(); it != plugins.end(); ++it) {
       if (it->name == ASCIIToUTF16(kFlashPluginName))
         paths->push_back(it->path);
     }
   }
 
-  static std::vector<webkit::WebPluginInfo> GetPlugins() {
-    std::vector<webkit::WebPluginInfo> plugins;
+  static std::vector<content::WebPluginInfo> GetPlugins() {
+    std::vector<content::WebPluginInfo> plugins;
     scoped_refptr<content::MessageLoopRunner> runner =
         new content::MessageLoopRunner;
     content::PluginService::GetInstance()->GetPlugins(
@@ -170,9 +170,9 @@
   }
 
   static void GetPluginsInfoCallback(
-      std::vector<webkit::WebPluginInfo>* rv,
+      std::vector<content::WebPluginInfo>* rv,
       const base::Closure& quit_task,
-      const std::vector<webkit::WebPluginInfo>& plugins) {
+      const std::vector<content::WebPluginInfo>& plugins) {
     *rv = plugins;
     quit_task.Run();
   }
@@ -252,7 +252,7 @@
 #endif
   };
 
-  std::vector<webkit::WebPluginInfo> plugins = GetPlugins();
+  std::vector<content::WebPluginInfo> plugins = GetPlugins();
   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(expected); ++i) {
     size_t j = 0;
     for (; j < plugins.size(); ++j) {
diff --git a/chrome/browser/chrome_quota_permission_context.cc b/chrome/browser/chrome_quota_permission_context.cc
index a85b677..804fa24 100644
--- a/chrome/browser/chrome_quota_permission_context.cc
+++ b/chrome/browser/chrome_quota_permission_context.cc
@@ -54,7 +54,6 @@
   // ConfirmInfoBarDelegate:
   virtual bool ShouldExpireInternal(
       const content::LoadCommittedDetails& details) const OVERRIDE;
-
   virtual string16 GetMessageText() const OVERRIDE;
   virtual bool Accept() OVERRIDE;
   virtual bool Cancel() OVERRIDE;
diff --git a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
index f31caa7..8b88552 100644
--- a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
+++ b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
@@ -84,7 +84,6 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/rlz/rlz.h"
-#include "chrome/browser/storage_monitor/storage_monitor_chromeos.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/chrome_version_info.h"
@@ -555,8 +554,6 @@
                                   base::Bind(&ChromeOSVersionCallback),
                                   &tracker_);
 
-  storage_monitor_.reset(new StorageMonitorCros());
-
   // Make sure that wallpaper boot transition and other delays in OOBE
   // are disabled for tests and kiosk app launch by default.
   // Individual tests may enable them if they want.
@@ -801,7 +798,6 @@
   power_button_observer_.reset();
   screensaver_controller_.reset();
   idle_action_warning_observer_.reset();
-  storage_monitor_.reset();
 
   // Delete ContactManager while |g_browser_process| is still alive.
   contact_manager_.reset();
diff --git a/chrome/browser/chromeos/chrome_browser_main_chromeos.h b/chrome/browser/chromeos/chrome_browser_main_chromeos.h
index f1073b0..df86349 100644
--- a/chrome/browser/chromeos/chrome_browser_main_chromeos.h
+++ b/chrome/browser/chromeos/chrome_browser_main_chromeos.h
@@ -31,7 +31,6 @@
 class ScreenLockObserver;
 class ScreensaverController;
 class SessionManagerObserver;
-class StorageMonitorCros;
 class SuspendObserver;
 class SwapMetrics;
 class UserActivityNotifier;
@@ -83,7 +82,6 @@
   scoped_ptr<content::PowerSaveBlocker> retail_mode_power_save_blocker_;
   scoped_ptr<UserActivityNotifier> user_activity_notifier_;
   scoped_ptr<VideoActivityNotifier> video_activity_notifier_;
-  scoped_ptr<StorageMonitorCros> storage_monitor_;
   scoped_ptr<IdleActionWarningObserver> idle_action_warning_observer_;
   scoped_ptr<SwapMetrics> swap_metrics_;
 
diff --git a/chrome/browser/chromeos/cros/cert_library.cc b/chrome/browser/chromeos/cros/cert_library.cc
index 952f14f..315c594 100644
--- a/chrome/browser/chromeos/cros/cert_library.cc
+++ b/chrome/browser/chromeos/cros/cert_library.cc
@@ -25,7 +25,7 @@
 #include "grit/generated_resources.h"
 #include "net/cert/cert_database.h"
 #include "net/cert/nss_cert_database.h"
-#include "third_party/icu/public/i18n/unicode/coll.h"  // icu::Collator
+#include "third_party/icu/source/i18n/unicode/coll.h"  // icu::Collator
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/l10n/l10n_util_collator.h"
 
diff --git a/chrome/browser/chromeos/cros/network_library_impl_base.cc b/chrome/browser/chromeos/cros/network_library_impl_base.cc
index f5a872c..1ea9f64 100644
--- a/chrome/browser/chromeos/cros/network_library_impl_base.cc
+++ b/chrome/browser/chromeos/cros/network_library_impl_base.cc
@@ -938,7 +938,7 @@
 class UserStringSubstitution : public onc::StringSubstitution {
  public:
   UserStringSubstitution() {}
-  virtual bool GetSubstitute(std::string placeholder,
+  virtual bool GetSubstitute(const std::string& placeholder,
                              std::string* substitute) const OVERRIDE {
     if (!UserManager::Get()->IsUserLoggedIn())
       return false;
@@ -1039,20 +1039,6 @@
         onc::TranslateONCObjectToShill(&onc::kNetworkConfigurationSignature,
                                        *normalized_network);
 
-    // Set the ProxyConfig.
-    const base::DictionaryValue* proxy_settings;
-    if (normalized_network->GetDictionaryWithoutPathExpansion(
-            onc::network_config::kProxySettings,
-            &proxy_settings)) {
-      scoped_ptr<base::DictionaryValue> proxy_config =
-          onc::ConvertOncProxySettingsToProxyConfig(*proxy_settings);
-      std::string proxy_json;
-      base::JSONWriter::Write(proxy_config.get(), &proxy_json);
-      shill_dict->SetStringWithoutPathExpansion(
-          flimflam::kProxyConfigProperty,
-          proxy_json);
-    }
-
     // Set the UIData.
     scoped_ptr<NetworkUIData> ui_data =
         NetworkUIData::CreateFromONC(source, *normalized_network);
diff --git a/chrome/browser/chromeos/display/display_preferences.cc b/chrome/browser/chromeos/display/display_preferences.cc
index 2650909..a6a6b89 100644
--- a/chrome/browser/chromeos/display/display_preferences.cc
+++ b/chrome/browser/chromeos/display/display_preferences.cc
@@ -182,7 +182,7 @@
 
   size_t num = display_manager->GetNumDisplays();
   for (size_t i = 0; i < num; ++i) {
-    int64 id = display_manager->GetDisplayAt(i)->id();
+    int64 id = display_manager->GetDisplayAt(i).id();
     ash::internal::DisplayInfo info = display_manager->GetDisplayInfo(id);
 
     scoped_ptr<base::DictionaryValue> property_value(
diff --git a/chrome/browser/chromeos/drive/drive_integration_service.cc b/chrome/browser/chromeos/drive/drive_integration_service.cc
index d4e6c53..6ae980a 100644
--- a/chrome/browser/chromeos/drive/drive_integration_service.cc
+++ b/chrome/browser/chromeos/drive/drive_integration_service.cc
@@ -15,7 +15,6 @@
 #include "chrome/browser/chromeos/drive/drive_app_registry.h"
 #include "chrome/browser/chromeos/drive/file_cache.h"
 #include "chrome/browser/chromeos/drive/file_system.h"
-#include "chrome/browser/chromeos/drive/file_system_proxy.h"
 #include "chrome/browser/chromeos/drive/file_system_util.h"
 #include "chrome/browser/chromeos/drive/file_write_helper.h"
 #include "chrome/browser/chromeos/drive/job_scheduler.h"
@@ -307,19 +306,15 @@
 
 void DriveIntegrationService::AddDriveMountPoint() {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  DCHECK(!file_system_proxy_.get());
 
   const base::FilePath drive_mount_point = util::GetDriveMountPointPath();
   fileapi::ExternalMountPoints* mount_points =
       BrowserContext::GetMountPoints(profile_);
   DCHECK(mount_points);
 
-  file_system_proxy_ = new FileSystemProxy(file_system_.get());
-
-  bool success = mount_points->RegisterRemoteFileSystem(
+  bool success = mount_points->RegisterFileSystem(
       drive_mount_point.BaseName().AsUTF8Unsafe(),
       fileapi::kFileSystemTypeDrive,
-      file_system_proxy_.get(),
       drive_mount_point);
 
   if (success) {
@@ -343,10 +338,6 @@
 
   mount_points->RevokeFileSystem(
       util::GetDriveMountPointPath().BaseName().AsUTF8Unsafe());
-  if (file_system_proxy_.get()) {
-    file_system_proxy_->DetachFromFileSystem();
-    file_system_proxy_ = NULL;
-  }
   util::Log("Drive mount point is removed");
 }
 
diff --git a/chrome/browser/chromeos/drive/drive_integration_service.h b/chrome/browser/chromeos/drive/drive_integration_service.h
index ac29cf9..56e15a9 100644
--- a/chrome/browser/chromeos/drive/drive_integration_service.h
+++ b/chrome/browser/chromeos/drive/drive_integration_service.h
@@ -29,7 +29,6 @@
 class DriveAppRegistry;
 class DriveServiceInterface;
 class FileSystemInterface;
-class FileSystemProxy;
 class FileWriteHelper;
 class JobListInterface;
 
@@ -117,7 +116,7 @@
   // Must be called on UI thread.
   bool IsDriveEnabled();
 
-  // Registers remote file system proxy for drive mount point.
+  // Registers remote file system for drive mount point.
   void AddDriveMountPoint();
   // Unregisters drive mount point from File API.
   void RemoveDriveMountPoint();
@@ -155,7 +154,6 @@
   scoped_ptr<FileSystemInterface> file_system_;
   scoped_ptr<FileWriteHelper> file_write_helper_;
   scoped_ptr<DownloadHandler> download_handler_;
-  scoped_refptr<FileSystemProxy> file_system_proxy_;
   scoped_ptr<DebugInfoCollector> debug_info_collector_;
 
   ObserverList<DriveIntegrationServiceObserver> observers_;
diff --git a/chrome/browser/chromeos/drive/file_system_backend_delegate.cc b/chrome/browser/chromeos/drive/file_system_backend_delegate.cc
index 12598d2..b2462fc 100644
--- a/chrome/browser/chromeos/drive/file_system_backend_delegate.cc
+++ b/chrome/browser/chromeos/drive/file_system_backend_delegate.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/chromeos/drive/file_system_backend_delegate.h"
 
 #include "base/bind.h"
+#include "base/files/file_path.h"
 #include "base/memory/scoped_ptr.h"
 #include "chrome/browser/chromeos/drive/async_file_util.h"
 #include "chrome/browser/chromeos/drive/file_system_util.h"
@@ -15,9 +16,9 @@
 #include "content/public/browser/browser_thread.h"
 #include "webkit/browser/blob/file_stream_reader.h"
 #include "webkit/browser/fileapi/async_file_util.h"
-#include "webkit/browser/fileapi/external_mount_points.h"
+#include "webkit/browser/fileapi/file_system_context.h"
 #include "webkit/browser/fileapi/file_system_task_runners.h"
-#include "webkit/browser/fileapi/remote_file_system_proxy.h"
+#include "webkit/browser/fileapi/file_system_url.h"
 
 using content::BrowserThread;
 
@@ -25,8 +26,7 @@
 
 FileSystemBackendDelegate::FileSystemBackendDelegate(
     content::BrowserContext* browser_context)
-    : mount_points_(content::BrowserContext::GetMountPoints(browser_context)),
-      profile_id_(Profile::FromBrowserContext(browser_context)),
+    : profile_id_(Profile::FromBrowserContext(browser_context)),
       async_file_util_(new internal::AsyncFileUtil(
           base::Bind(&util::GetFileSystemByProfileId, profile_id_))) {
   DCHECK(profile_id_);
@@ -70,14 +70,14 @@
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
   DCHECK_EQ(fileapi::kFileSystemTypeDrive, url.type());
 
-  fileapi::RemoteFileSystemProxyInterface* proxy =
-      mount_points_->GetRemoteFileSystemProxy(url.filesystem_id());
-  if (!proxy)
+  base::FilePath file_path = util::ExtractDrivePathFromFileSystemUrl(url);
+  if (file_path.empty())
     return scoped_ptr<fileapi::FileStreamWriter>();
 
   return scoped_ptr<fileapi::FileStreamWriter>(
       new internal::WebkitFileStreamWriterImpl(
-          proxy, url, offset, context->task_runners()->file_task_runner()));
+          base::Bind(&util::GetFileSystemByProfileId, profile_id_),
+          context->task_runners()->file_task_runner(),file_path, offset));
 }
 
 }  // namespace drive
diff --git a/chrome/browser/chromeos/drive/file_system_backend_delegate.h b/chrome/browser/chromeos/drive/file_system_backend_delegate.h
index 55a9916..50066d3 100644
--- a/chrome/browser/chromeos/drive/file_system_backend_delegate.h
+++ b/chrome/browser/chromeos/drive/file_system_backend_delegate.h
@@ -6,7 +6,6 @@
 #define CHROME_BROWSER_CHROMEOS_DRIVE_FILE_SYSTEM_BACKEND_DELEGATE_H_
 
 #include "base/basictypes.h"
-#include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "chrome/browser/chromeos/fileapi/file_system_backend_delegate.h"
 
@@ -16,7 +15,6 @@
 
 namespace fileapi {
 class AsyncFileUtil;
-class ExternalMountPoints;
 }  // namespace fileapi
 
 namespace drive {
@@ -25,9 +23,8 @@
 // for Drive file system.
 class FileSystemBackendDelegate : public chromeos::FileSystemBackendDelegate {
  public:
-  // |browser_context| is currently used to take the ExternalMountPoints.
-  explicit FileSystemBackendDelegate(
-      content::BrowserContext* browser_context);
+  // |browser_context| is used to obtain |profile_id_|.
+  explicit FileSystemBackendDelegate(content::BrowserContext* browser_context);
   virtual ~FileSystemBackendDelegate();
 
   // FileSystemBackend::Delegate overrides.
@@ -44,8 +41,6 @@
       fileapi::FileSystemContext* context) OVERRIDE;
 
  private:
-  scoped_refptr<fileapi::ExternalMountPoints> mount_points_;
-
   // The profile for processing Drive accesses. Should not be NULL.
   void* profile_id_;
   scoped_ptr<fileapi::AsyncFileUtil> async_file_util_;
diff --git a/chrome/browser/chromeos/drive/file_system_interface.h b/chrome/browser/chromeos/drive/file_system_interface.h
index bf3b3be..0c2b40b 100644
--- a/chrome/browser/chromeos/drive/file_system_interface.h
+++ b/chrome/browser/chromeos/drive/file_system_interface.h
@@ -37,12 +37,14 @@
 
 // Struct to represent a search result for SearchMetadata().
 struct MetadataSearchResult {
-  MetadataSearchResult(const base::FilePath& in_path,
-                       const ResourceEntry& in_entry,
+  MetadataSearchResult(const ResourceEntry& in_entry,
                        const std::string& in_highlighted_base_name)
-      : path(in_path),
-        entry(in_entry),
+      : entry(in_entry),
         highlighted_base_name(in_highlighted_base_name) {
+    // Note: |path| is set separately from |entry| or other fields, because
+    // getting path typically takes longer time hence we want to fill it only
+    // when it is necessary. (I.e., not for temporary candidates, just for
+    // final user visible results.)
   }
 
   // The two members are used to create FileEntry object.
diff --git a/chrome/browser/chromeos/drive/file_system_proxy.cc b/chrome/browser/chromeos/drive/file_system_proxy.cc
deleted file mode 100644
index 25214f5..0000000
--- a/chrome/browser/chromeos/drive/file_system_proxy.cc
+++ /dev/null
@@ -1,445 +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/file_system_proxy.h"
-
-#include <string>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/platform_file.h"
-#include "base/strings/string_util.h"
-#include "base/threading/sequenced_worker_pool.h"
-#include "base/values.h"
-#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"
-#include "content/public/browser/browser_thread.h"
-#include "webkit/browser/blob/file_stream_reader.h"
-#include "webkit/browser/fileapi/file_system_url.h"
-#include "webkit/common/blob/shareable_file_reference.h"
-#include "webkit/common/fileapi/file_system_types.h"
-#include "webkit/common/fileapi/file_system_util.h"
-
-using base::MessageLoopProxy;
-using content::BrowserThread;
-using fileapi::DirectoryEntry;
-using fileapi::FileSystemURL;
-using fileapi::FileSystemOperation;
-using webkit_blob::ShareableFileReference;
-
-namespace drive {
-
-namespace {
-
-// Runs |callback| with |error|, |file| and |peer_handle|.
-void RunOpenFileCallback(
-    base::ProcessHandle peer_handle,
-    const fileapi::RemoteFileSystemProxyInterface::OpenFileCallback& callback,
-    base::PlatformFileError error,
-    base::PlatformFile file) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-
-  callback.Run(error, file, peer_handle);
-}
-
-// 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,
-    const base::FilePath& local_path,
-    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));
-
-  scoped_refptr<webkit_blob::ShareableFileReference> file_reference =
-      webkit_blob::ShareableFileReference::GetOrCreate(webkit_blob::ScopedFile(
-          local_path,
-          scope_out_policy,
-          BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE)
-              .get()));
-  callback.Run(error, file_info, local_path, file_reference);
-}
-
-}  // namespace
-
-FileSystemProxy::FileSystemProxy(
-    FileSystemInterface* file_system)
-    : file_system_(file_system) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-}
-
-void FileSystemProxy::DetachFromFileSystem() {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  file_system_ = NULL;
-}
-
-void FileSystemProxy::GetFileInfo(
-    const FileSystemURL& file_url,
-    const FileSystemOperation::GetMetadataCallback& callback) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-  base::FilePath file_path;
-  if (!ValidateUrl(file_url, &file_path)) {
-    MessageLoopProxy::current()->PostTask(
-        FROM_HERE,
-        base::Bind(callback,
-                   base::PLATFORM_FILE_ERROR_NOT_FOUND,
-                   base::PlatformFileInfo()));
-    return;
-  }
-
-  CallFileApiInternalFunctionOnUIThread(
-      base::Bind(&fileapi_internal::GetFileInfo,
-                 file_path, google_apis::CreateRelayCallback(callback)));
-}
-
-void FileSystemProxy::Copy(
-    const FileSystemURL& src_file_url,
-    const FileSystemURL& dest_file_url,
-    const FileSystemOperation::StatusCallback& callback) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-
-  base::FilePath src_file_path, dest_file_path;
-  if (!ValidateUrl(src_file_url, &src_file_path) ||
-      !ValidateUrl(dest_file_url, &dest_file_path)) {
-    MessageLoopProxy::current()->PostTask(
-        FROM_HERE,
-        base::Bind(callback, base::PLATFORM_FILE_ERROR_NOT_FOUND));
-    return;
-  }
-
-  CallFileApiInternalFunctionOnUIThread(
-      base::Bind(&fileapi_internal::Copy,
-                 src_file_path, dest_file_path,
-                 google_apis::CreateRelayCallback(callback)));
-}
-
-void FileSystemProxy::Move(
-    const FileSystemURL& src_file_url,
-    const FileSystemURL& dest_file_url,
-    const FileSystemOperation::StatusCallback& callback) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-
-  base::FilePath src_file_path, dest_file_path;
-  if (!ValidateUrl(src_file_url, &src_file_path) ||
-      !ValidateUrl(dest_file_url, &dest_file_path)) {
-    MessageLoopProxy::current()->PostTask(
-        FROM_HERE,
-        base::Bind(callback, base::PLATFORM_FILE_ERROR_NOT_FOUND));
-    return;
-  }
-
-  CallFileApiInternalFunctionOnUIThread(
-      base::Bind(&fileapi_internal::Move,
-                 src_file_path, dest_file_path,
-                 google_apis::CreateRelayCallback(callback)));
-}
-
-void FileSystemProxy::ReadDirectory(
-    const FileSystemURL& file_url,
-    const FileSystemOperation::ReadDirectoryCallback& callback) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-
-  base::FilePath file_path;
-  if (!ValidateUrl(file_url, &file_path)) {
-    base::MessageLoopProxy::current()->PostTask(
-        FROM_HERE,
-        base::Bind(callback,
-                   base::PLATFORM_FILE_ERROR_NOT_FOUND,
-                   std::vector<DirectoryEntry>(),
-                   false));
-    return;
-  }
-
-  CallFileApiInternalFunctionOnUIThread(
-      base::Bind(&fileapi_internal::ReadDirectory,
-                 file_path, google_apis::CreateRelayCallback(callback)));
-}
-
-void FileSystemProxy::Remove(
-    const FileSystemURL& file_url,
-    bool recursive,
-    const FileSystemOperation::StatusCallback& callback) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-
-  base::FilePath file_path;
-  if (!ValidateUrl(file_url, &file_path)) {
-    MessageLoopProxy::current()->PostTask(
-        FROM_HERE,
-        base::Bind(callback, base::PLATFORM_FILE_ERROR_NOT_FOUND));
-    return;
-  }
-
-  CallFileApiInternalFunctionOnUIThread(
-      base::Bind(&fileapi_internal::Remove,
-                 file_path, recursive,
-                 google_apis::CreateRelayCallback(callback)));
-}
-
-void FileSystemProxy::CreateDirectory(
-    const FileSystemURL& file_url,
-    bool exclusive,
-    bool recursive,
-    const FileSystemOperation::StatusCallback& callback) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-
-  base::FilePath file_path;
-  if (!ValidateUrl(file_url, &file_path)) {
-    MessageLoopProxy::current()->PostTask(
-        FROM_HERE,
-        base::Bind(callback, base::PLATFORM_FILE_ERROR_NOT_FOUND));
-    return;
-  }
-
-  CallFileApiInternalFunctionOnUIThread(
-      base::Bind(&fileapi_internal::CreateDirectory,
-                 file_path, exclusive, recursive,
-                 google_apis::CreateRelayCallback(callback)));
-}
-
-void FileSystemProxy::CreateFile(
-    const FileSystemURL& file_url,
-    bool exclusive,
-    const FileSystemOperation::StatusCallback& callback) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-
-  base::FilePath file_path;
-  if (!ValidateUrl(file_url, &file_path)) {
-    MessageLoopProxy::current()->PostTask(
-        FROM_HERE,
-        base::Bind(callback, base::PLATFORM_FILE_ERROR_NOT_FOUND));
-    return;
-  }
-
-  CallFileApiInternalFunctionOnUIThread(
-      base::Bind(&fileapi_internal::CreateFile,
-                 file_path, exclusive,
-                 google_apis::CreateRelayCallback(callback)));
-}
-
-void FileSystemProxy::Truncate(
-    const FileSystemURL& file_url,
-    int64 length,
-    const FileSystemOperation::StatusCallback& callback) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-
-  base::FilePath file_path;
-  if (!ValidateUrl(file_url, &file_path)) {
-    MessageLoopProxy::current()->PostTask(
-        FROM_HERE,
-        base::Bind(callback, base::PLATFORM_FILE_ERROR_NOT_FOUND));
-    return;
-  }
-
-  CallFileApiInternalFunctionOnUIThread(
-      base::Bind(&fileapi_internal::Truncate,
-                 file_path, length,
-                 google_apis::CreateRelayCallback(callback)));
-}
-
-void FileSystemProxy::OpenFile(
-    const FileSystemURL& file_url,
-    int file_flags,
-    base::ProcessHandle peer_handle,
-    const OpenFileCallback& callback) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-
-  base::FilePath file_path;
-  if (!ValidateUrl(file_url, &file_path)) {
-    MessageLoopProxy::current()->PostTask(
-        FROM_HERE,
-        base::Bind(callback,
-                   base::PLATFORM_FILE_ERROR_NOT_FOUND,
-                   base::kInvalidPlatformFileValue,
-                   peer_handle));
-    return;
-  }
-
-  CallFileApiInternalFunctionOnUIThread(
-      base::Bind(&fileapi_internal::OpenFile,
-                 file_path, file_flags,
-                 google_apis::CreateRelayCallback(
-                     base::Bind(&RunOpenFileCallback, peer_handle, callback))));
-}
-
-void FileSystemProxy::NotifyCloseFile(const FileSystemURL& url) {
-  base::FilePath file_path;
-  if (!ValidateUrl(url, &file_path))
-    return;
-
-  CallFileApiInternalFunctionOnUIThread(
-      base::Bind(&fileapi_internal::CloseFile, file_path));
-}
-
-void FileSystemProxy::TouchFile(
-    const fileapi::FileSystemURL& url,
-    const base::Time& last_access_time,
-    const base::Time& last_modified_time,
-    const FileSystemOperation::StatusCallback& callback) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-
-  base::FilePath file_path;
-  if (!ValidateUrl(url, &file_path))
-    return;
-
-  CallFileApiInternalFunctionOnUIThread(
-      base::Bind(&fileapi_internal::TouchFile,
-                 file_path, last_access_time, last_modified_time,
-                 google_apis::CreateRelayCallback(callback)));
-}
-
-void FileSystemProxy::CreateSnapshotFile(
-    const FileSystemURL& file_url,
-    const FileSystemOperation::SnapshotFileCallback& callback) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-
-  base::FilePath file_path;
-  if (!ValidateUrl(file_url, &file_path)) {
-    MessageLoopProxy::current()->PostTask(
-        FROM_HERE,
-        base::Bind(callback,
-                   base::PLATFORM_FILE_ERROR_NOT_FOUND,
-                   base::PlatformFileInfo(),
-                   base::FilePath(),
-                   scoped_refptr<ShareableFileReference>()));
-    return;
-  }
-
-  CallFileApiInternalFunctionOnUIThread(
-      base::Bind(&fileapi_internal::CreateSnapshotFile,
-                 file_path,
-                 google_apis::CreateRelayCallback(
-                     base::Bind(&RunSnapshotFileCallback, callback))));
-}
-
-void FileSystemProxy::CreateWritableSnapshotFile(
-    const FileSystemURL& file_url,
-    const fileapi::WritableSnapshotFile& callback) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-
-  base::FilePath file_path;
-  if (!ValidateUrl(file_url, &file_path)) {
-    MessageLoopProxy::current()->PostTask(
-        FROM_HERE,
-        base::Bind(callback,
-                   base::PLATFORM_FILE_ERROR_NOT_FOUND,
-                   base::FilePath(),
-                   scoped_refptr<ShareableFileReference>(NULL)));
-    return;
-  }
-
-  CallFileSystemMethodOnUIThread(
-      base::Bind(&FileSystemInterface::OpenFile,
-                 base::Unretained(file_system_),
-                 file_path,
-                 OPEN_FILE,
-                 google_apis::CreateRelayCallback(
-                     base::Bind(
-                         &FileSystemProxy::OnCreateWritableSnapshotFile,
-                         this,
-                         file_path,
-                         callback))));
-}
-
-scoped_ptr<webkit_blob::FileStreamReader>
-FileSystemProxy::CreateFileStreamReader(
-    base::SequencedTaskRunner* file_task_runner,
-    const fileapi::FileSystemURL& url,
-    int64 offset,
-    const base::Time& expected_modification_time) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-
-  NOTREACHED();
-  return scoped_ptr<webkit_blob::FileStreamReader>();
-}
-
-FileSystemProxy::~FileSystemProxy() {
-  // Should be deleted from the FileSystemBackend on UI thread.
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-}
-
-// static.
-bool FileSystemProxy::ValidateUrl(
-    const FileSystemURL& url, base::FilePath* file_path) {
-  *file_path = util::ExtractDrivePathFromFileSystemUrl(url);
-  return !file_path->empty();
-}
-
-void FileSystemProxy::CallFileSystemMethodOnUIThread(
-    const base::Closure& method_call) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-  BrowserThread::PostTask(
-      BrowserThread::UI,
-      FROM_HERE,
-      base::Bind(
-          &FileSystemProxy::CallFileSystemMethodOnUIThreadInternal,
-          this,
-          method_call));
-}
-
-void FileSystemProxy::CallFileSystemMethodOnUIThreadInternal(
-    const base::Closure& method_call) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  // If |file_system_| is NULL, it means the file system has already shut down.
-  if (file_system_)
-    method_call.Run();
-}
-
-void FileSystemProxy::CallFileApiInternalFunctionOnUIThread(
-    const base::Callback<void(FileSystemInterface*)>& function) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-  BrowserThread::PostTask(
-      BrowserThread::UI,
-      FROM_HERE,
-      base::Bind(
-          &fileapi_internal::RunFileSystemCallback,
-          base::Bind(&FileSystemProxy::GetFileSystemOnUIThread, this),
-          function, base::Closure()));
-}
-
-void FileSystemProxy::OnCreateWritableSnapshotFile(
-    const base::FilePath& virtual_path,
-    const fileapi::WritableSnapshotFile& callback,
-    FileError result,
-    const base::FilePath& local_path) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-
-  scoped_refptr<ShareableFileReference> file_ref;
-
-  if (result == FILE_ERROR_OK) {
-    file_ref = ShareableFileReference::GetOrCreate(
-        local_path,
-        ShareableFileReference::DONT_DELETE_ON_FINAL_RELEASE,
-        BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE).get());
-    file_ref->AddFinalReleaseCallback(
-        base::Bind(&FileSystemProxy::CloseWritableSnapshotFile,
-                   this,
-                   virtual_path));
-  }
-
-  callback.Run(FileErrorToPlatformError(result), local_path, file_ref);
-}
-
-void FileSystemProxy::CloseWritableSnapshotFile(
-    const base::FilePath& virtual_path,
-    const base::FilePath& local_path) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-
-  CallFileApiInternalFunctionOnUIThread(
-      base::Bind(&fileapi_internal::CloseFile, virtual_path));
-}
-
-FileSystemInterface* FileSystemProxy::GetFileSystemOnUIThread() {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  return file_system_;
-}
-
-}  // namespace drive
diff --git a/chrome/browser/chromeos/drive/file_system_proxy.h b/chrome/browser/chromeos/drive/file_system_proxy.h
deleted file mode 100644
index 349c5c0..0000000
--- a/chrome/browser/chromeos/drive/file_system_proxy.h
+++ /dev/null
@@ -1,148 +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_FILE_SYSTEM_PROXY_H_
-#define CHROME_BROWSER_CHROMEOS_DRIVE_FILE_SYSTEM_PROXY_H_
-
-#include "chrome/browser/chromeos/drive/file_errors.h"
-#include "webkit/browser/fileapi/remote_file_system_proxy.h"
-
-namespace fileapi {
-class FileSystemURL;
-}  // namespace fileapi
-
-namespace drive {
-
-class FileSystemInterface;
-class ResourceEntry;
-
-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 {
- public:
-  using fileapi::RemoteFileSystemProxyInterface::OpenFileCallback;
-
-  // |file_system| is the FileSystem instance owned by DriveIntegrationService.
-  explicit FileSystemProxy(FileSystemInterface* file_system);
-
-  // Detaches this instance from |file_system_|.
-  // Method calls may result in no-op after calling this method.
-  // This method must be called on UI thread.
-  void DetachFromFileSystem();
-
-  // fileapi::RemoteFileSystemProxyInterface overrides.
-  virtual void GetFileInfo(
-      const fileapi::FileSystemURL& url,
-      const fileapi::FileSystemOperation::GetMetadataCallback&
-          callback) OVERRIDE;
-  virtual void Copy(
-      const fileapi::FileSystemURL& src_url,
-      const fileapi::FileSystemURL& dest_url,
-      const fileapi::FileSystemOperation::StatusCallback& callback)
-          OVERRIDE;
-  virtual void Move(
-      const fileapi::FileSystemURL& src_url,
-      const fileapi::FileSystemURL& dest_url,
-      const fileapi::FileSystemOperation::StatusCallback& callback)
-          OVERRIDE;
-  virtual void ReadDirectory(const fileapi::FileSystemURL& url,
-     const fileapi::FileSystemOperation::ReadDirectoryCallback&
-         callback) OVERRIDE;
-  virtual void Remove(
-      const fileapi::FileSystemURL& url, bool recursive,
-      const fileapi::FileSystemOperation::StatusCallback& callback)
-          OVERRIDE;
-  virtual void CreateDirectory(
-      const fileapi::FileSystemURL& file_url,
-      bool exclusive,
-      bool recursive,
-      const fileapi::FileSystemOperation::StatusCallback& callback)
-          OVERRIDE;
-  virtual void CreateFile(
-      const fileapi::FileSystemURL& file_url,
-      bool exclusive,
-      const fileapi::FileSystemOperation::StatusCallback& callback)
-          OVERRIDE;
-  virtual void Truncate(
-      const fileapi::FileSystemURL& file_url, int64 length,
-      const fileapi::FileSystemOperation::StatusCallback& callback)
-          OVERRIDE;
-  virtual void CreateSnapshotFile(
-      const fileapi::FileSystemURL& url,
-      const fileapi::FileSystemOperation::SnapshotFileCallback&
-      callback) OVERRIDE;
-  virtual void CreateWritableSnapshotFile(
-      const fileapi::FileSystemURL& url,
-      const fileapi::WritableSnapshotFile& callback) OVERRIDE;
-  virtual void OpenFile(
-      const fileapi::FileSystemURL& url,
-      int file_flags,
-      base::ProcessHandle peer_handle,
-      const OpenFileCallback& callback) OVERRIDE;
-  virtual void NotifyCloseFile(const fileapi::FileSystemURL& url) OVERRIDE;
-  virtual void TouchFile(
-      const fileapi::FileSystemURL& url,
-      const base::Time& last_access_time,
-      const base::Time& last_modified_time,
-      const fileapi::FileSystemOperation::StatusCallback& callback)
-          OVERRIDE;
-  virtual scoped_ptr<webkit_blob::FileStreamReader> CreateFileStreamReader(
-      base::SequencedTaskRunner* file_task_runner,
-      const fileapi::FileSystemURL& url,
-      int64 offset,
-      const base::Time& expected_modification_time) OVERRIDE;
-
- protected:
-  virtual ~FileSystemProxy();
-
- private:
-  // Checks if a given |url| belongs to this file system. If it does,
-  // the call will return true and fill in |file_path| with a file path of
-  // a corresponding element within this file system.
-  static bool ValidateUrl(const fileapi::FileSystemURL& url,
-                          base::FilePath* file_path);
-
-  // Helper method to call methods of FileSystem. This method aborts
-  // method calls in case DetachFromFileSystem() has been called.
-  void CallFileSystemMethodOnUIThread(const base::Closure& method_call);
-
-  // Used to implement CallFileSystemMethodOnUIThread.
-  void CallFileSystemMethodOnUIThreadInternal(
-      const base::Closure& method_call);
-
-  // Helper method to call drive::filapi_internal functions. This method
-  // aborts calls in case DetachFromFileSystem() has been called.
-  void CallFileApiInternalFunctionOnUIThread(
-      const base::Callback<void(FileSystemInterface*)>& function);
-
-  // Helper callback for relaying reply for CreateWritableSnapshotFile() to
-  // the calling thread.
-  void OnCreateWritableSnapshotFile(
-      const base::FilePath& virtual_path,
-      const fileapi::WritableSnapshotFile& callback,
-      FileError result,
-      const base::FilePath& local_path);
-
-  // Helper callback for closing the local cache file and committing the dirty
-  // flag. This is triggered when the callback for CreateWritableSnapshotFile
-  // released the refcounted reference to the file.
-  void CloseWritableSnapshotFile(
-      const base::FilePath& virtual_path,
-      const base::FilePath& local_path);
-
-  // Returns |file_system_| on UI thread.
-  FileSystemInterface* GetFileSystemOnUIThread();
-
-  FileSystemInterface* file_system_;
-};
-
-}  // namespace drive
-
-#endif  // CHROME_BROWSER_CHROMEOS_DRIVE_FILE_SYSTEM_PROXY_H_
diff --git a/chrome/browser/chromeos/drive/fileapi_worker.cc b/chrome/browser/chromeos/drive/fileapi_worker.cc
index 825a19b..9f59917 100644
--- a/chrome/browser/chromeos/drive/fileapi_worker.cc
+++ b/chrome/browser/chromeos/drive/fileapi_worker.cc
@@ -132,6 +132,15 @@
   callback.Run(base::PLATFORM_FILE_OK, file_info, local_path, scope_out_policy);
 }
 
+// Runs |callback| with arguments converted from |error| and |local_path|.
+void RunCreateWritableSnapshotFileCallback(
+    const CreateWritableSnapshotFileCallback& callback,
+    FileError error,
+    const base::FilePath& local_path) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  callback.Run(FileErrorToPlatformError(error), local_path);
+}
+
 // Runs |callback| with |error| and |platform_file|.
 void RunOpenFileCallback(const OpenFileCallback& callback,
                          base::PlatformFileError* error,
@@ -296,6 +305,17 @@
       base::Bind(&RunCreateSnapshotFileCallback, callback));
 }
 
+void CreateWritableSnapshotFile(
+    const base::FilePath& file_path,
+    const CreateWritableSnapshotFileCallback& callback,
+    FileSystemInterface* file_system) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  file_system->OpenFile(
+      file_path,
+      OPEN_FILE,
+      base::Bind(&RunCreateWritableSnapshotFileCallback, callback));
+}
+
 void OpenFile(const base::FilePath& file_path,
               int file_flags,
               const OpenFileCallback& callback,
diff --git a/chrome/browser/chromeos/drive/fileapi_worker.h b/chrome/browser/chromeos/drive/fileapi_worker.h
index c97a511..d26c65e 100644
--- a/chrome/browser/chromeos/drive/fileapi_worker.h
+++ b/chrome/browser/chromeos/drive/fileapi_worker.h
@@ -61,6 +61,10 @@
     CreateSnapshotFileCallback;
 typedef base::Callback<
     void(base::PlatformFileError result,
+         const base::FilePath& snapshot_file_path)>
+    CreateWritableSnapshotFileCallback;
+typedef base::Callback<
+    void(base::PlatformFileError result,
          base::PlatformFile platform_file)> OpenFileCallback;
 
 // Runs |file_system_getter| to obtain the instance of FileSystemInstance,
@@ -143,6 +147,13 @@
                         const CreateSnapshotFileCallback& callback,
                         FileSystemInterface* file_system);
 
+// Creates a writable snapshot for the file at |file_path|.
+// After writing operation is done, CloseFile is needed to be called.
+void CreateWritableSnapshotFile(
+    const base::FilePath& file_path,
+    const CreateWritableSnapshotFileCallback& callback,
+    FileSystemInterface* file_system);
+
 // Opens the file at |file_path| with options |file_flags|.
 // Called from FileSystemProxy::OpenFile.
 void OpenFile(const base::FilePath& file_path,
diff --git a/chrome/browser/chromeos/drive/search_metadata.cc b/chrome/browser/chromeos/drive/search_metadata.cc
index 6623d2e..b49f47f 100644
--- a/chrome/browser/chromeos/drive/search_metadata.cc
+++ b/chrome/browser/chromeos/drive/search_metadata.cc
@@ -145,14 +145,10 @@
       (query && !FindAndHighlight(entry.base_name(), query, &highlighted)))
     return;
 
-  base::FilePath path = resource_metadata->GetFilePath(entry.resource_id());
-  if (path.empty())
-    return;
-
   // Make space for |entry| when appropriate.
   if (result_candidates->size() == at_most_num_matches)
     result_candidates->pop();
-  result_candidates->push(new MetadataSearchResult(path, entry, highlighted));
+  result_candidates->push(new MetadataSearchResult(entry, highlighted));
 }
 
 // Implements SearchMetadata().
@@ -181,8 +177,17 @@
   // Prepare the result.
   scoped_ptr<MetadataSearchResultVector> results(
       new MetadataSearchResultVector);
-  for (; !result_candidates.empty(); result_candidates.pop())
+  for (; !result_candidates.empty(); result_candidates.pop()) {
+    // The path field of entries in result_candidates are empty at this point,
+    // because we don't want to run the expensive metadata DB look up except for
+    // the final results. Hence, here we fill the part.
+    base::FilePath path = resource_metadata->GetFilePath(
+        result_candidates.top()->entry.resource_id());
+    if (path.empty())
+      continue;
     results->push_back(*result_candidates.top());
+    results->back().path = path;
+  }
 
   // Reverse the order here because |result_candidates| puts the most
   // uninteresting candidate at the top.
diff --git a/chrome/browser/chromeos/drive/webkit_file_stream_writer_impl.cc b/chrome/browser/chromeos/drive/webkit_file_stream_writer_impl.cc
index 87a54fd..94e8e80 100644
--- a/chrome/browser/chromeos/drive/webkit_file_stream_writer_impl.cc
+++ b/chrome/browser/chromeos/drive/webkit_file_stream_writer_impl.cc
@@ -4,65 +4,109 @@
 
 #include "chrome/browser/chromeos/drive/webkit_file_stream_writer_impl.h"
 
+#include "base/bind.h"
 #include "base/callback_helpers.h"
+#include "chrome/browser/chromeos/drive/file_system_util.h"
+#include "chrome/browser/chromeos/drive/fileapi_worker.h"
+#include "chrome/browser/google_apis/task_util.h"
+#include "content/public/browser/browser_thread.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"
+
+using content::BrowserThread;
 
 namespace drive {
 namespace internal {
+namespace {
+
+// Creates a writable snapshot file of the |drive_path|.
+void CreateWritableSnapshotFile(
+    const WebkitFileStreamWriterImpl::FileSystemGetter& file_system_getter,
+    const base::FilePath& drive_path,
+    const fileapi_internal::CreateWritableSnapshotFileCallback& callback) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+
+  BrowserThread::PostTask(
+      BrowserThread::UI,
+      FROM_HERE,
+      base::Bind(
+          &fileapi_internal::RunFileSystemCallback,
+          file_system_getter,
+          base::Bind(&fileapi_internal::CreateWritableSnapshotFile,
+                     drive_path, google_apis::CreateRelayCallback(callback)),
+          google_apis::CreateRelayCallback(base::Bind(
+              callback, base::PLATFORM_FILE_ERROR_FAILED, base::FilePath()))));
+}
+
+// Closes the writable snapshot file opened by CreateWritableSnapshotFile.
+// TODO(hidehiko): Get rid of this function. crbug.com/259184.
+void CloseFile(
+    const WebkitFileStreamWriterImpl::FileSystemGetter& file_system_getter,
+    const base::FilePath& drive_path) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+
+  BrowserThread::PostTask(
+      BrowserThread::UI,
+      FROM_HERE,
+      base::Bind(&fileapi_internal::RunFileSystemCallback,
+                 file_system_getter,
+                 base::Bind(&fileapi_internal::CloseFile, drive_path),
+                 base::Closure()));
+}
+
+}  // namespace
 
 WebkitFileStreamWriterImpl::WebkitFileStreamWriterImpl(
-    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),
+    const FileSystemGetter& file_system_getter,
+    base::TaskRunner* file_task_runner,
+    const base::FilePath& file_path,
+    int64 offset)
+    : file_system_getter_(file_system_getter),
+      file_task_runner_(file_task_runner),
+      file_path_(file_path),
+      offset_(offset),
       weak_ptr_factory_(this) {
 }
 
 WebkitFileStreamWriterImpl::~WebkitFileStreamWriterImpl() {
+  if (local_file_writer_) {
+    // If the file is opened, close it at destructor.
+    // It is necessary to close the local file in advance.
+    local_file_writer_.reset();
+    CloseFile(file_system_getter_, file_path_);
+  }
 }
 
 int WebkitFileStreamWriterImpl::Write(net::IOBuffer* buf,
                                       int buf_len,
                                       const net::CompletionCallback& callback) {
-  DCHECK(!has_pending_create_snapshot_);
+  DCHECK(pending_write_callback_.is_null());
   DCHECK(pending_cancel_callback_.is_null());
+  DCHECK(!callback.is_null());
 
   // If the local file is already available, just delegate to it.
   if (local_file_writer_)
     return local_file_writer_->Write(buf, buf_len, callback);
 
-  // In this WebkitFileStreamWriterImpl, 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
-  // WriteAfterCreateWritableSnapshotFile, from the destructor of
-  // WebkitFileStreamWriterImpl.
-  has_pending_create_snapshot_ = true;
-  remote_filesystem_->CreateWritableSnapshotFile(
-      url_,
+  // The local file is not yet ready. Create the writable snapshot.
+  if (file_path_.empty())
+    return net::ERR_FILE_NOT_FOUND;
+
+  pending_write_callback_ = callback;
+  CreateWritableSnapshotFile(
+      file_system_getter_, file_path_,
       base::Bind(
           &WebkitFileStreamWriterImpl::WriteAfterCreateWritableSnapshotFile,
-          weak_ptr_factory_.GetWeakPtr(),
-          make_scoped_refptr(buf),
-          buf_len,
-          callback));
+          weak_ptr_factory_.GetWeakPtr(), make_scoped_refptr(buf), buf_len));
   return net::ERR_IO_PENDING;
 }
 
 int WebkitFileStreamWriterImpl::Cancel(
     const net::CompletionCallback& callback) {
-  DCHECK(!callback.is_null());
   DCHECK(pending_cancel_callback_.is_null());
+  DCHECK(!callback.is_null());
 
   // If LocalFileWriter is already created, just delegate the cancel to it.
   if (local_file_writer_)
@@ -70,7 +114,9 @@
 
   // If file open operation is in-flight, wait for its completion and cancel
   // further write operation in WriteAfterCreateWritableSnapshotFile.
-  if (has_pending_create_snapshot_) {
+  if (!pending_write_callback_.is_null()) {
+    // Dismiss pending write callback immediately.
+    pending_write_callback_.Reset();
     pending_cancel_callback_ = callback;
     return net::ERR_IO_PENDING;
   }
@@ -80,15 +126,15 @@
 }
 
 int WebkitFileStreamWriterImpl::Flush(const net::CompletionCallback& callback) {
-  DCHECK(!callback.is_null());
   DCHECK(pending_cancel_callback_.is_null());
+  DCHECK(!callback.is_null());
 
   // If LocalFileWriter is already created, just delegate to it.
   if (local_file_writer_)
     return local_file_writer_->Flush(callback);
 
   // There shouldn't be in-flight Write operation.
-  DCHECK(!has_pending_create_snapshot_);
+  DCHECK(pending_write_callback_.is_null());
 
   // Here is the case Flush() is called before any Write() invocation.
   // Do nothing.
@@ -99,30 +145,36 @@
 void WebkitFileStreamWriterImpl::WriteAfterCreateWritableSnapshotFile(
     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;
+    const base::FilePath& local_path) {
+  DCHECK(!local_file_writer_);
+
   if (!pending_cancel_callback_.is_null()) {
+    DCHECK(pending_write_callback_.is_null());
     // Cancel() is called during the creation of the snapshot file.
     // Don't write to the file.
+    if (open_result == base::PLATFORM_FILE_OK) {
+      // Here the file is internally created. To revert the operation, close
+      // the file.
+      DCHECK(!local_path.empty());
+      CloseFile(file_system_getter_, file_path_);
+    }
+
     base::ResetAndReturn(&pending_cancel_callback_).Run(net::OK);
     return;
   }
 
+  DCHECK(!pending_write_callback_.is_null());
+
+  const net::CompletionCallback callback =
+      base::ResetAndReturn(&pending_write_callback_);
   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_);
   local_file_writer_.reset(new fileapi::LocalFileStreamWriter(
-      local_task_runner_.get(), local_path, initial_offset_));
+      file_task_runner_.get(), local_path, offset_));
   int result = local_file_writer_->Write(buf, buf_len, callback);
   if (result != net::ERR_IO_PENDING)
     callback.Run(result);
diff --git a/chrome/browser/chromeos/drive/webkit_file_stream_writer_impl.h b/chrome/browser/chromeos/drive/webkit_file_stream_writer_impl.h
index 38bfa54..1ddadba 100644
--- a/chrome/browser/chromeos/drive/webkit_file_stream_writer_impl.h
+++ b/chrome/browser/chromeos/drive/webkit_file_stream_writer_impl.h
@@ -6,43 +6,44 @@
 #define CHROME_BROWSER_CHROMEOS_DRIVE_WEBKIT_FILE_STREAM_WRITER_IMPL_H_
 
 #include "base/basictypes.h"
-#include "base/files/file_path.h"
+#include "base/callback.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 base {
+class FilePath;
+class TaskRunner;
+}  // namespace base
 
 namespace net {
 class IOBuffer;
-}
-
-namespace webkit_blob {
-class ShareableFileReference;
-}
+}  // namespace net
 
 namespace drive {
+
+class FileSystemInterface;
+
 namespace internal {
 
 // The implementation of fileapi::FileStreamWriter for the Drive File System.
 class WebkitFileStreamWriterImpl : 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.
-  WebkitFileStreamWriterImpl(
-      const scoped_refptr<fileapi::RemoteFileSystemProxyInterface>&
-          remote_filesystem,
-      const fileapi::FileSystemURL& url,
-      int64 offset,
-      base::TaskRunner* local_task_runner);
+  // Callback to return the FileSystemInterface instance. This is an
+  // injecting point for testing.
+  // Note that the callback will be copied between threads (IO and UI), and
+  // will be called on UI thread.
+  typedef base::Callback<FileSystemInterface*()> FileSystemGetter;
+
+  // Creates a writer for a file at |file_path| on FileSystem returned by
+  // |file_system_getter| that starts writing from |offset|.
+  // When invalid parameters are set, the first call to Write() method fails.
+  // Uses |file_task_runner| for local file operations.
+  WebkitFileStreamWriterImpl(const FileSystemGetter& file_system_getter,
+                             base::TaskRunner* file_task_runner,
+                             const base::FilePath& file_path,
+                             int64 offset);
   virtual ~WebkitFileStreamWriterImpl();
 
   // FileWriter override.
@@ -52,23 +53,20 @@
   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.
+  // Part of Write(). Called after CreateWritableSnapshotFile is completed.
   void WriteAfterCreateWritableSnapshotFile(
       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);
+      const base::FilePath& local_path);
 
-  scoped_refptr<fileapi::RemoteFileSystemProxyInterface> remote_filesystem_;
-  scoped_refptr<base::TaskRunner> local_task_runner_;
-  const fileapi::FileSystemURL url_;
-  const int64 initial_offset_;
+  FileSystemGetter file_system_getter_;
+  scoped_refptr<base::TaskRunner> file_task_runner_;
+  const base::FilePath file_path_;
+  const int64 offset_;
+
   scoped_ptr<fileapi::FileStreamWriter> local_file_writer_;
-  scoped_refptr<webkit_blob::ShareableFileReference> file_ref_;
-  bool has_pending_create_snapshot_;
+  net::CompletionCallback pending_write_callback_;
   net::CompletionCallback pending_cancel_callback_;
 
   // Note: This should remain the last member so it'll be destroyed and
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 c81be45..35f3f6a 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
@@ -2024,6 +2024,7 @@
              IDS_FILE_BROWSER_ZIP_TARGET_EXISTS_ERROR);
   SET_STRING("ZIP_FILESYSTEM_ERROR", IDS_FILE_BROWSER_ZIP_FILESYSTEM_ERROR);
   SET_STRING("ZIP_UNEXPECTED_ERROR", IDS_FILE_BROWSER_ZIP_UNEXPECTED_ERROR);
+  SET_STRING("SHARE_ERROR", IDS_FILE_BROWSER_SHARE_ERROR);
 
   SET_STRING("DELETED_MESSAGE_PLURAL", IDS_FILE_BROWSER_DELETED_MESSAGE_PLURAL);
   SET_STRING("DELETED_MESSAGE", IDS_FILE_BROWSER_DELETED_MESSAGE);
diff --git a/chrome/browser/chromeos/extensions/file_manager/file_manager_event_router.cc b/chrome/browser/chromeos/extensions/file_manager/file_manager_event_router.cc
index 927eaa2..487ea2d 100644
--- a/chrome/browser/chromeos/extensions/file_manager/file_manager_event_router.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/file_manager_event_router.cc
@@ -176,6 +176,30 @@
   return result.Pass();
 }
 
+// Checks for availability of the Google+ Photos app.
+bool IsGooglePhotosInstalled(Profile *profile) {
+  ExtensionService* service =
+      extensions::ExtensionSystem::Get(profile)->extension_service();
+  if (!service)
+    return false;
+
+  // Google+ Photos uses several ids for different channels. Therefore, all of
+  // them should be checked.
+  const std::string kGooglePlusPhotosIds[] = {
+    "ebpbnabdhheoknfklmpddcdijjkmklkp",  // G+ Photos staging
+    "efjnaogkjbogokcnohkmnjdojkikgobo",  // G+ Photos prod
+    "ejegoaikibpmikoejfephaneibodccma"   // G+ Photos dev
+  };
+
+  for (size_t i = 0; i < arraysize(kGooglePlusPhotosIds); ++i) {
+    if (service->GetExtensionById(kGooglePlusPhotosIds[i],
+                                  false /* include_disable */) != NULL)
+      return true;
+  }
+
+  return false;
+}
+
 }  // namespace
 
 // Pass dummy value to JobInfo's constructor for make it default constructible.
@@ -716,24 +740,11 @@
   const base::FilePath dcim_path = mount_path.Append(
       FILE_PATH_LITERAL("DCIM"));
 
-  // TODO(mtomasz): Temporarily for M26. Remove it on M27.
-  // If an external photo importer is installed, then do not show the action
-  // choice dialog.
-  ExtensionService* service =
-      extensions::ExtensionSystem::Get(profile_)->extension_service();
-  if (!service)
-    return;
-  const std::string kExternalPhotoImporterExtensionId =
-      "efjnaogkjbogokcnohkmnjdojkikgobo";
-  const bool external_photo_importer_available =
-      service->GetExtensionById(kExternalPhotoImporterExtensionId,
-                                false /* include_disable */) != NULL;
-
   // If there is no DCIM folder or an external photo importer is not available,
   // then launch Files.app.
   DirectoryExistsOnUIThread(
       dcim_path,
-      external_photo_importer_available ?
+      IsGooglePhotosInstalled(profile_) ?
         base::Bind(&base::DoNothing) :
         base::Bind(&file_manager_util::ViewRemovableDrive, mount_path),
       base::Bind(&file_manager_util::ViewRemovableDrive, mount_path));
diff --git a/chrome/browser/chromeos/extensions/file_manager/file_manager_util.cc b/chrome/browser/chromeos/extensions/file_manager/file_manager_util.cc
index 4ce88d2..c698bfc 100644
--- a/chrome/browser/chromeos/extensions/file_manager/file_manager_util.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/file_manager_util.cc
@@ -49,6 +49,7 @@
 #include "content/public/browser/user_metrics.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/pepper_plugin_info.h"
+#include "content/public/common/webplugininfo.h"
 #include "grit/generated_resources.h"
 #include "net/base/escape.h"
 #include "net/base/mime_util.h"
@@ -60,7 +61,6 @@
 #include "webkit/browser/fileapi/file_system_operation_runner.h"
 #include "webkit/browser/fileapi/file_system_url.h"
 #include "webkit/common/fileapi/file_system_util.h"
-#include "webkit/plugins/webplugininfo.h"
 
 using base::DictionaryValue;
 using base::ListValue;
@@ -480,7 +480,7 @@
 void CheckIfDirectoryExistsOnIOThread(
     scoped_refptr<fileapi::FileSystemContext> file_system_context,
     const GURL& url,
-    const fileapi::FileSystemOperation::StatusCallback& callback) {
+    const fileapi::FileSystemOperationRunner::StatusCallback& callback) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
 
   fileapi::FileSystemURL file_system_url = file_system_context->CrackURL(url);
@@ -492,7 +492,7 @@
 void CheckIfDirectoryExists(
     scoped_refptr<fileapi::FileSystemContext> file_system_context,
     const GURL& url,
-    const fileapi::FileSystemOperation::StatusCallback& callback) {
+    const fileapi::FileSystemOperationRunner::StatusCallback& callback) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 
   BrowserThread::PostTask(
diff --git a/chrome/browser/chromeos/extensions/wallpaper_private_apitest.cc b/chrome/browser/chromeos/extensions/wallpaper_private_apitest.cc
index 14f164f..80fbb8b 100644
--- a/chrome/browser/chromeos/extensions/wallpaper_private_apitest.cc
+++ b/chrome/browser/chromeos/extensions/wallpaper_private_apitest.cc
@@ -5,7 +5,8 @@
 #include "chrome/browser/extensions/extension_apitest.h"
 #include "net/dns/mock_host_resolver.h"
 
-IN_PROC_BROWSER_TEST_F(ExtensionApiTest, WallpaperPicker) {
+// Flaky. See http://crbug.com/262854 .
+IN_PROC_BROWSER_TEST_F(ExtensionApiTest, DISABLED_WallpaperPicker) {
   host_resolver()->AddRule("a.com", "127.0.0.1");
   ASSERT_TRUE(StartEmbeddedTestServer());
   ASSERT_TRUE(RunComponentExtensionTest("wallpaper_manager")) << message_;
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 4f21a46..fcb8919 100644
--- a/chrome/browser/chromeos/input_method/input_method_manager_impl.cc
+++ b/chrome/browser/chromeos/input_method/input_method_manager_impl.cc
@@ -23,7 +23,7 @@
 #include "chromeos/ime/extension_ime_util.h"
 #include "chromeos/ime/input_method_delegate.h"
 #include "chromeos/ime/xkeyboard.h"
-#include "third_party/icu/public/common/unicode/uloc.h"
+#include "third_party/icu/source/common/unicode/uloc.h"
 #include "ui/base/accelerators/accelerator.h"
 
 namespace chromeos {
diff --git a/chrome/browser/chromeos/login/chrome_restart_request.cc b/chrome/browser/chromeos/login/chrome_restart_request.cc
index b2106f3..d8f2671 100644
--- a/chrome/browser/chromeos/login/chrome_restart_request.cc
+++ b/chrome/browser/chromeos/login/chrome_restart_request.cc
@@ -139,8 +139,10 @@
       ash::switches::kAshDefaultGuestWallpaperSmall,
       ash::switches::kAshDefaultWallpaperLarge,
       ash::switches::kAshDefaultWallpaperSmall,
+#if defined(OS_CHROMEOS)
+      ash::switches::kAshDisableAudioDeviceMenu,
       ash::switches::kAshDisableNewAudioHandler,
-      ash::switches::kAshEnableAudioDeviceMenu,
+#endif
       ash::switches::kAshHostWindowBounds,
       ash::switches::kAshTouchHud,
       ash::switches::kAuraLegacyPowerButton,
@@ -149,6 +151,7 @@
       // content/browser/renderer_host/render_process_host_impl.cc.
       cc::switches::kBackgroundColorInsteadOfCheckerboard,
       cc::switches::kCompositeToMailbox,
+      cc::switches::kDisableCompositedAntialiasing,
       cc::switches::kDisableImplSidePainting,
       cc::switches::kDisableThreadedAnimation,
       cc::switches::kEnableImplSidePainting,
diff --git a/chrome/browser/chromeos/login/existing_user_controller.cc b/chrome/browser/chromeos/login/existing_user_controller.cc
index 3d64d4a..c1e14ee 100644
--- a/chrome/browser/chromeos/login/existing_user_controller.cc
+++ b/chrome/browser/chromeos/login/existing_user_controller.cc
@@ -715,6 +715,7 @@
 
   if (UserManager::Get()->GetUserFlow(last_login_attempt_username_)->
           HandleLoginFailure(failure)) {
+    login_display_->SetUIEnabled(true);
     return;
   }
 
diff --git a/chrome/browser/chromeos/login/login_display_host_impl.cc b/chrome/browser/chromeos/login/login_display_host_impl.cc
index fa60389..96d92a4 100644
--- a/chrome/browser/chromeos/login/login_display_host_impl.cc
+++ b/chrome/browser/chromeos/login/login_display_host_impl.cc
@@ -151,6 +151,9 @@
 // static
 LoginDisplayHost* LoginDisplayHostImpl::default_host_ = NULL;
 
+// static
+const int LoginDisplayHostImpl::kShowLoginWebUIid = 0x1111;
+
 ////////////////////////////////////////////////////////////////////////////////
 // LoginDisplayHostImpl, public
 
@@ -439,8 +442,10 @@
   }
   LOG(WARNING) << "Login WebUI >> sign in";
 
-  if (!login_window_)
+  if (!login_window_) {
+    TRACE_EVENT_ASYNC_BEGIN0("ui", "ShowLoginWebUI", kShowLoginWebUIid);
     LoadURL(GURL(kLoginURL));
+  }
 
   DVLOG(1) << "Starting sign in screen";
   const chromeos::UserList& users = chromeos::UserManager::Get()->GetUsers();
diff --git a/chrome/browser/chromeos/login/login_display_host_impl.h b/chrome/browser/chromeos/login/login_display_host_impl.h
index 481001c..8d25d3f 100644
--- a/chrome/browser/chromeos/login/login_display_host_impl.h
+++ b/chrome/browser/chromeos/login/login_display_host_impl.h
@@ -84,6 +84,10 @@
 
   const gfx::Rect& background_bounds() const { return background_bounds_; }
 
+  // Trace id for ShowLoginWebUI event (since there exists at most one login
+  // WebUI at a time).
+  static const int kShowLoginWebUIid;
+
  protected:
   // content::NotificationObserver implementation:
   virtual void Observe(int type,
diff --git a/chrome/browser/chromeos/login/managed/locally_managed_user_login_flow.h b/chrome/browser/chromeos/login/managed/locally_managed_user_login_flow.h
index 688f07e..8a038f1 100644
--- a/chrome/browser/chromeos/login/managed/locally_managed_user_login_flow.h
+++ b/chrome/browser/chromeos/login/managed/locally_managed_user_login_flow.h
@@ -7,6 +7,7 @@
 
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
+#include "base/memory/weak_ptr.h"
 #include "base/strings/string16.h"
 #include "chrome/browser/chromeos/login/user_flow.h"
 
diff --git a/chrome/browser/chromeos/login/wallpaper_manager.h b/chrome/browser/chromeos/login/wallpaper_manager.h
index 62e00d7..c994aba 100644
--- a/chrome/browser/chromeos/login/wallpaper_manager.h
+++ b/chrome/browser/chromeos/login/wallpaper_manager.h
@@ -21,7 +21,7 @@
 #include "chromeos/dbus/power_manager_client.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
-#include "third_party/icu/public/i18n/unicode/timezone.h"
+#include "third_party/icu/source/i18n/unicode/timezone.h"
 #include "ui/gfx/image/image_skia.h"
 
 class PrefRegistrySimple;
diff --git a/chrome/browser/chromeos/login/wallpaper_manager_browsertest.cc b/chrome/browser/chromeos/login/wallpaper_manager_browsertest.cc
index ff25663..210aaa2 100644
--- a/chrome/browser/chromeos/login/wallpaper_manager_browsertest.cc
+++ b/chrome/browser/chromeos/login/wallpaper_manager_browsertest.cc
@@ -32,8 +32,8 @@
 
 namespace {
 
-const int kLargeWallpaperResourceId = IDR_AURA_WALLPAPERS_5_GRADIENT5_LARGE;
-const int kSmallWallpaperResourceId = IDR_AURA_WALLPAPERS_5_GRADIENT5_SMALL;
+const int kLargeWallpaperResourceId = IDR_AURA_WALLPAPER_DEFAULT_LARGE;
+const int kSmallWallpaperResourceId = IDR_AURA_WALLPAPER_DEFAULT_SMALL;
 
 int kLargeWallpaperWidth = 256;
 int kLargeWallpaperHeight = ash::kLargeWallpaperMaxHeight;
diff --git a/chrome/browser/chromeos/login/wizard_controller_browsertest.cc b/chrome/browser/chromeos/login/wizard_controller_browsertest.cc
index aab384d..60aff4b 100644
--- a/chrome/browser/chromeos/login/wizard_controller_browsertest.cc
+++ b/chrome/browser/chromeos/login/wizard_controller_browsertest.cc
@@ -33,7 +33,7 @@
 #include "grit/generated_resources.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/icu/public/common/unicode/locid.h"
+#include "third_party/icu/source/common/unicode/locid.h"
 #include "ui/base/accelerators/accelerator.h"
 #include "ui/base/l10n/l10n_util.h"
 
diff --git a/chrome/browser/chromeos/net/network_portal_detector_impl.cc b/chrome/browser/chromeos/net/network_portal_detector_impl.cc
index f6e3c0a..5a1bbef 100644
--- a/chrome/browser/chromeos/net/network_portal_detector_impl.cc
+++ b/chrome/browser/chromeos/net/network_portal_detector_impl.cc
@@ -201,6 +201,8 @@
   if (!lazy_detection_enabled())
     return;
   lazy_detection_enabled_ = false;
+  if (attempt_count_ == kMaxRequestAttempts && IsPortalCheckPending())
+    CancelPortalDetection();
   VLOG(1) << "Lazy detection mode disabled.";
 }
 
diff --git a/chrome/browser/chromeos/net/network_portal_detector_impl.h b/chrome/browser/chromeos/net/network_portal_detector_impl.h
index eeeef2e..b3a1371 100644
--- a/chrome/browser/chromeos/net/network_portal_detector_impl.h
+++ b/chrome/browser/chromeos/net/network_portal_detector_impl.h
@@ -138,7 +138,13 @@
 
   // Returns current number of portal detection attempts.
   // Used by unit tests.
-  int attempt_count_for_testing() { return attempt_count_; }
+  int attempt_count_for_testing() const { return attempt_count_; }
+
+  // Sets current number of detection attempts.
+  // Used by unit tests.
+  void set_attempt_count_for_testing(int attempt_count) {
+    attempt_count_ = attempt_count;
+  }
 
   // Sets minimum time between consecutive portal checks for the same
   // network. Used by unit tests.
@@ -159,7 +165,7 @@
   }
 
   // Returns delay before next portal check. Used by unit tests.
-  const base::TimeDelta& next_attempt_delay_for_testing() {
+  const base::TimeDelta& next_attempt_delay_for_testing() const {
     return next_attempt_delay_;
   }
 
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 7c30aba..2b6b410 100644
--- a/chrome/browser/chromeos/net/network_portal_detector_impl_unittest.cc
+++ b/chrome/browser/chromeos/net/network_portal_detector_impl_unittest.cc
@@ -149,6 +149,10 @@
     return network_portal_detector()->attempt_count_for_testing();
   }
 
+  void set_attempt_count(int ac) {
+    return network_portal_detector()->set_attempt_count_for_testing(ac);
+  }
+
   void set_min_time_between_attempts(const base::TimeDelta& delta) {
     network_portal_detector()->set_min_time_between_attempts_for_testing(delta);
   }
@@ -550,6 +554,17 @@
                    kStubWireless1);
 }
 
+TEST_F(NetworkPortalDetectorImplTest, DisableLazyDetectionWhilePendingRequest) {
+  ASSERT_TRUE(is_state_idle());
+  set_attempt_count(3);
+  enable_lazy_detection();
+  ASSERT_TRUE(is_state_portal_detection_pending());
+  disable_lazy_detection();
+
+  // To run CaptivePortalDetector::DetectCaptivePortal().
+  base::MessageLoop::current()->RunUntilIdle();
+}
+
 TEST_F(NetworkPortalDetectorImplTest, LazyDetectionForOnlineNetwork) {
   ASSERT_TRUE(is_state_idle());
   set_min_time_between_attempts(base::TimeDelta());
diff --git a/chrome/browser/chromeos/net/onc_utils.cc b/chrome/browser/chromeos/net/onc_utils.cc
index 430af00..f897272 100644
--- a/chrome/browser/chromeos/net/onc_utils.cc
+++ b/chrome/browser/chromeos/net/onc_utils.cc
@@ -6,6 +6,8 @@
 
 #include "base/logging.h"
 #include "base/values.h"
+#include "chrome/browser/chromeos/login/user.h"
+#include "chrome/browser/chromeos/login/user_manager.h"
 #include "chrome/browser/chromeos/ui_proxy_config.h"
 #include "chrome/browser/prefs/proxy_config_dictionary.h"
 #include "chromeos/network/onc/onc_utils.h"
@@ -125,5 +127,53 @@
   return proxy_dict.Pass();
 }
 
+namespace {
+
+// This class defines which string placeholders of ONC are replaced by which
+// user attribute.
+class UserStringSubstitution : public chromeos::onc::StringSubstitution {
+ public:
+  explicit UserStringSubstitution(const chromeos::User* user) : user_(user) {}
+  virtual ~UserStringSubstitution() {}
+
+  virtual bool GetSubstitute(const std::string& placeholder,
+                             std::string* substitute) const OVERRIDE {
+    if (placeholder == chromeos::onc::substitutes::kLoginIDField)
+      *substitute = user_->GetAccountName(false);
+    else if (placeholder == chromeos::onc::substitutes::kEmailField)
+      *substitute = user_->email();
+    else
+      return false;
+    return true;
+  }
+
+ private:
+  const chromeos::User* user_;
+
+  DISALLOW_COPY_AND_ASSIGN(UserStringSubstitution);
+};
+
+const chromeos::User* GetLoggedInUserByHash(const std::string& userhash) {
+  const chromeos::UserList& users =
+      chromeos::UserManager::Get()->GetLoggedInUsers();
+  for (chromeos::UserList::const_iterator it = users.begin(); it != users.end();
+       ++it) {
+    if ((*it)->username_hash() == userhash)
+      return *it;
+  }
+  return NULL;
+}
+
+}  // namespace
+
+void ExpandStringPlaceholdersInNetworksForUser(
+    const std::string& hashed_username,
+    base::ListValue* network_configs) {
+  const chromeos::User* user = GetLoggedInUserByHash(hashed_username);
+  DCHECK(user);
+  UserStringSubstitution substitution(user);
+  chromeos::onc::ExpandStringsInNetworks(substitution, network_configs);
+}
+
 }  // namespace onc
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/net/onc_utils.h b/chrome/browser/chromeos/net/onc_utils.h
index d283e87..e855494 100644
--- a/chrome/browser/chromeos/net/onc_utils.h
+++ b/chrome/browser/chromeos/net/onc_utils.h
@@ -5,17 +5,17 @@
 #ifndef CHROME_BROWSER_CHROMEOS_NET_ONC_UTILS_H_
 #define CHROME_BROWSER_CHROMEOS_NET_ONC_UTILS_H_
 
+#include <string>
+
 #include "base/memory/scoped_ptr.h"
 #include "chromeos/network/onc/onc_constants.h"
 
 namespace base {
 class DictionaryValue;
+class ListValue;
 }
 
 namespace chromeos {
-
-class NetworkUIData;
-
 namespace onc {
 
 // Translates |onc_proxy_settings|, which has to be a valid ONC ProxySettings
@@ -27,6 +27,14 @@
 scoped_ptr<base::DictionaryValue> ConvertOncProxySettingsToProxyConfig(
     const base::DictionaryValue& onc_proxy_settings);
 
+// Replaces string placeholders in |network_configs|, which must be a list of
+// ONC NetworkConfigurations. Currently only user name placeholders are
+// implemented, which are replaced by attributes of the logged-in user with
+// |hashed_username|.
+void ExpandStringPlaceholdersInNetworksForUser(
+    const std::string& hashed_username,
+    base::ListValue* network_configs);
+
 }  // namespace onc
 }  // namespace chromeos
 
diff --git a/chrome/browser/chromeos/net/proxy_config_handler.cc b/chrome/browser/chromeos/net/proxy_config_handler.cc
index adb4c86..865d664 100644
--- a/chrome/browser/chromeos/net/proxy_config_handler.cc
+++ b/chrome/browser/chromeos/net/proxy_config_handler.cc
@@ -7,12 +7,17 @@
 #include "base/bind.h"
 #include "base/json/json_writer.h"
 #include "base/logging.h"
+#include "base/prefs/pref_registry_simple.h"
+#include "base/prefs/pref_service.h"
 #include "base/values.h"
+#include "chrome/browser/chromeos/net/onc_utils.h"
 #include "chrome/browser/prefs/proxy_config_dictionary.h"
 #include "chrome/common/pref_names.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/shill_service_client.h"
 #include "chromeos/network/network_handler_callbacks.h"
+#include "chromeos/network/network_profile.h"
+#include "chromeos/network/network_profile_handler.h"
 #include "chromeos/network/network_state.h"
 #include "chromeos/network/network_state_handler.h"
 #include "components/user_prefs/pref_registry_syncable.h"
@@ -21,10 +26,124 @@
 
 namespace chromeos {
 
+namespace {
+
+const base::DictionaryValue* GetNetworkConfigByGUID(
+    const base::ListValue& network_configs,
+    const std::string& guid) {
+  for (base::ListValue::const_iterator it = network_configs.begin();
+       it != network_configs.end();
+       ++it) {
+    const base::DictionaryValue* network = NULL;
+    (*it)->GetAsDictionary(&network);
+    std::string current_guid;
+    network->GetStringWithoutPathExpansion(onc::network_config::kGUID,
+                                           &current_guid);
+    if (current_guid == guid)
+      return network;
+  }
+  return NULL;
+}
+
+scoped_ptr<ProxyConfigDictionary> GetProxyPolicy(
+    const PrefService* pref_service,
+    const char* pref_name,
+    const NetworkState& network,
+    bool* network_is_managed) {
+  *network_is_managed = false;
+
+  if (!pref_service || network.guid().empty())
+    return scoped_ptr<ProxyConfigDictionary>();
+
+  if (!pref_service->IsManagedPreference(pref_name)) {
+    // No policy set.
+    return scoped_ptr<ProxyConfigDictionary>();
+  }
+
+  const base::ListValue* onc_policy = pref_service->GetList(pref_name);
+  if (!onc_policy) {
+    LOG(ERROR) << "Pref " << pref_name << " is managed, but no value is set.";
+    return scoped_ptr<ProxyConfigDictionary>();
+  }
+
+  const base::DictionaryValue* network_policy =
+      GetNetworkConfigByGUID(*onc_policy, network.guid());
+  if (!network_policy) {
+    // This network isn't managed by this policy.
+    return scoped_ptr<ProxyConfigDictionary>();
+  }
+
+  const base::DictionaryValue* proxy_policy = NULL;
+  network_policy->GetDictionaryWithoutPathExpansion(
+      onc::network_config::kProxySettings, &proxy_policy);
+  if (!proxy_policy) {
+    // This policy doesn't set a proxy for this network. Nonetheless, this
+    // disallows changes by the user.
+    *network_is_managed = true;
+    return scoped_ptr<ProxyConfigDictionary>();
+  }
+
+  scoped_ptr<base::DictionaryValue> proxy_dict =
+      onc::ConvertOncProxySettingsToProxyConfig(*proxy_policy);
+  *network_is_managed = true;
+  return make_scoped_ptr(new ProxyConfigDictionary(proxy_dict.get()));
+}
+
+}  // namespace
+
 namespace proxy_config {
 
 scoped_ptr<ProxyConfigDictionary> GetProxyConfigForNetwork(
-    const NetworkState& network) {
+    const PrefService* profile_prefs,
+    const PrefService* local_state_prefs,
+    const NetworkState& network,
+    onc::ONCSource* onc_source) {
+  VLOG(2) << "GetProxyConfigForNetwork network: " << network.path()
+          << " , guid: " << network.guid();
+  *onc_source = onc::ONC_SOURCE_NONE;
+  bool network_is_managed = false;
+
+  scoped_ptr<ProxyConfigDictionary> proxy_config =
+      GetProxyPolicy(profile_prefs,
+                     prefs::kOpenNetworkConfiguration,
+                     network,
+                     &network_is_managed);
+  if (network_is_managed) {
+    VLOG(1) << "Network " << network.path() << " is managed by user policy.";
+    *onc_source = onc::ONC_SOURCE_USER_POLICY;
+    return proxy_config.Pass();
+  }
+  proxy_config = GetProxyPolicy(local_state_prefs,
+                                prefs::kDeviceOpenNetworkConfiguration,
+                                network,
+                                &network_is_managed);
+  if (network_is_managed) {
+    VLOG(1) << "Network " << network.path() << " is managed by device policy.";
+    *onc_source = onc::ONC_SOURCE_DEVICE_POLICY;
+    return proxy_config.Pass();
+  }
+
+  if (network.profile_path().empty())
+    return scoped_ptr<ProxyConfigDictionary>();
+
+  const NetworkProfile* profile = NetworkHandler::Get()
+      ->network_profile_handler()->GetProfileForPath(network.profile_path());
+  if (!profile) {
+    LOG(WARNING) << "Unknown profile_path '" << network.profile_path() << "'.";
+    return scoped_ptr<ProxyConfigDictionary>();
+  }
+  if (!profile_prefs && profile->type() == NetworkProfile::TYPE_USER) {
+    // This case occurs, for example, if called from the proxy config tracker
+    // created for the system request context and the signin screen. Both don't
+    // use profile prefs and shouldn't depend on the user's not shared proxy
+    // settings.
+    VLOG(1)
+        << "Don't use unshared settings for system context or signin screen.";
+    return scoped_ptr<ProxyConfigDictionary>();
+  }
+
+  // No policy set for this network, read instead the user's (shared or
+  // unshared) configuration.
   const base::DictionaryValue& value = network.proxy_config();
   if (value.empty())
     return scoped_ptr<ProxyConfigDictionary>();
@@ -46,7 +165,8 @@
         base::Bind(&base::DoNothing),
         base::Bind(&network_handler::ShillErrorCallbackFunction,
                    "SetProxyConfig.ClearProperty Failed",
-                   network.path(), network_handler::ErrorCallback()));
+                   network.path(),
+                   network_handler::ErrorCallback()));
   } else {
     std::string proxy_config_str;
     base::JSONWriter::Write(&proxy_config.GetDictionary(), &proxy_config_str);
@@ -57,21 +177,28 @@
         base::Bind(&base::DoNothing),
         base::Bind(&network_handler::ShillErrorCallbackFunction,
                    "SetProxyConfig.SetProperty Failed",
-                   network.path(), network_handler::ErrorCallback()));
+                   network.path(),
+                   network_handler::ErrorCallback()));
   }
 
   if (NetworkHandler::IsInitialized()) {
-    NetworkHandler::Get()->network_state_handler()->
-        RequestUpdateForNetwork(network.path());
+    NetworkHandler::Get()->network_state_handler()
+        ->RequestUpdateForNetwork(network.path());
   }
 }
 
-void RegisterProfilePrefs(
-    user_prefs::PrefRegistrySyncable* registry) {
+void RegisterPrefs(PrefRegistrySimple* registry) {
+  registry->RegisterListPref(prefs::kDeviceOpenNetworkConfiguration);
+}
+
+void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) {
   registry->RegisterBooleanPref(
       prefs::kUseSharedProxies,
       false,
       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
+
+  registry->RegisterListPref(prefs::kOpenNetworkConfiguration,
+                             user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
 }
 
 }  // namespace proxy_config
diff --git a/chrome/browser/chromeos/net/proxy_config_handler.h b/chrome/browser/chromeos/net/proxy_config_handler.h
index b8455dc..40635d3 100644
--- a/chrome/browser/chromeos/net/proxy_config_handler.h
+++ b/chrome/browser/chromeos/net/proxy_config_handler.h
@@ -6,7 +6,10 @@
 #define CHROME_BROWSER_CHROMEOS_NET_PROXY_CONFIG_HANDLER_H_
 
 #include "base/memory/scoped_ptr.h"
+#include "chromeos/network/onc/onc_constants.h"
 
+class PrefRegistrySimple;
+class PrefService;
 class ProxyConfigDictionary;
 
 namespace user_prefs {
@@ -19,12 +22,21 @@
 
 namespace proxy_config {
 
+// Get the proxy configuration including per-network policies for network
+// |network|. If |profile_prefs| is NULL, then only shared settings (and device
+// policy) are respected. This is e.g. the case for the signin screen and the
+// system request context.
 scoped_ptr<ProxyConfigDictionary> GetProxyConfigForNetwork(
-    const NetworkState& network);
+    const PrefService* profile_prefs,
+    const PrefService* local_state_prefs,
+    const NetworkState& network,
+    onc::ONCSource* onc_source);
 
 void SetProxyConfigForNetwork(const ProxyConfigDictionary& proxy_config,
                               const NetworkState& network);
 
+void RegisterPrefs(PrefRegistrySimple* registry);
+
 void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
 
 }  // namespace proxy_config
diff --git a/chrome/browser/chromeos/offline/offline_load_page.cc b/chrome/browser/chromeos/offline/offline_load_page.cc
index d752d1d..2a12636 100644
--- a/chrome/browser/chromeos/offline/offline_load_page.cc
+++ b/chrome/browser/chromeos/offline/offline_load_page.cc
@@ -113,8 +113,7 @@
       extensions::ExtensionSystem::Get(profile)->extension_service();
   // Extension service does not exist in test.
   if (extensions_service)
-    extension = extensions_service->extensions()->GetHostedAppByURL(
-        ExtensionURLInfo(url_));
+    extension = extensions_service->extensions()->GetHostedAppByURL(url_);
 
   if (extension)
     GetAppOfflineStrings(extension, &strings);
diff --git a/chrome/browser/chromeos/options/network_config_view.cc b/chrome/browser/chromeos/options/network_config_view.cc
index ad5e37f..8de2ba7 100644
--- a/chrome/browser/chromeos/options/network_config_view.cc
+++ b/chrome/browser/chromeos/options/network_config_view.cc
@@ -286,6 +286,14 @@
                                  : gfx::Size();
 }
 
+// static
+const base::DictionaryValue* NetworkConfigView::FindPolicyForActiveUser(
+    const Network* network,
+    onc::ONCSource* onc_source) {
+  *onc_source = network->ui_data().onc_source();
+  return NetworkLibrary::Get()->FindOncForNetwork(network->unique_id());
+}
+
 void ControlledSettingIndicatorView::Layout() {
   image_view_->SetBounds(0, 0, width(), height());
 }
diff --git a/chrome/browser/chromeos/options/network_config_view.h b/chrome/browser/chromeos/options/network_config_view.h
index 8e5954f..0a8290b 100644
--- a/chrome/browser/chromeos/options/network_config_view.h
+++ b/chrome/browser/chromeos/options/network_config_view.h
@@ -74,6 +74,10 @@
     delegate_ = delegate;
   }
 
+  static const base::DictionaryValue* FindPolicyForActiveUser(
+      const Network* network,
+      onc::ONCSource* onc_source);
+
  protected:
   // views::View overrides:
   virtual void Layout() OVERRIDE;
diff --git a/chrome/browser/chromeos/options/vpn_config_view.cc b/chrome/browser/chromeos/options/vpn_config_view.cc
index 943e781..d8e019b 100644
--- a/chrome/browser/chromeos/options/vpn_config_view.cc
+++ b/chrome/browser/chromeos/options/vpn_config_view.cc
@@ -900,13 +900,14 @@
                                        Network* network,
                                        const std::string& dict_key,
                                        const std::string& key) {
-  NetworkLibrary* network_library = NetworkLibrary::Get();
+  onc::ONCSource onc_source = onc::ONC_SOURCE_NONE;
   const base::DictionaryValue* onc =
-      network_library->FindOncForNetwork(network->unique_id());
-  VLOG_IF(1, !onc) << "No ONC found for VPN network " << network->unique_id();
+      NetworkConfigView::FindPolicyForActiveUser(network, &onc_source);
 
+  VLOG_IF(1, !onc) << "No ONC found for VPN network " << network->unique_id();
   property_ui_data->ParseOncProperty(
-      network->ui_data().onc_source(), onc,
+      onc_source,
+      onc,
       base::StringPrintf("%s.%s.%s",
                          onc::network_config::kVPN,
                          dict_key.c_str(),
diff --git a/chrome/browser/chromeos/options/wifi_config_view.cc b/chrome/browser/chromeos/options/wifi_config_view.cc
index b2338e7..211f728 100644
--- a/chrome/browser/chromeos/options/wifi_config_view.cc
+++ b/chrome/browser/chromeos/options/wifi_config_view.cc
@@ -1246,10 +1246,13 @@
     NetworkPropertyUIData* property_ui_data,
     Network* network,
     const std::string& key) {
-  NetworkLibrary* network_library = NetworkLibrary::Get();
+  onc::ONCSource onc_source = onc::ONC_SOURCE_NONE;
+  const base::DictionaryValue* onc =
+      NetworkConfigView::FindPolicyForActiveUser(network, &onc_source);
+
   property_ui_data->ParseOncProperty(
-      network->ui_data().onc_source(),
-      network_library->FindOncForNetwork(network->unique_id()),
+      onc_source,
+      onc,
       base::StringPrintf("%s.%s", onc::network_config::kWiFi, key.c_str()));
 }
 
diff --git a/chrome/browser/chromeos/policy/configuration_policy_handler_chromeos.cc b/chrome/browser/chromeos/policy/configuration_policy_handler_chromeos.cc
index 81844f2..3fb1382 100644
--- a/chrome/browser/chromeos/policy/configuration_policy_handler_chromeos.cc
+++ b/chrome/browser/chromeos/policy/configuration_policy_handler_chromeos.cc
@@ -35,14 +35,18 @@
 NetworkConfigurationPolicyHandler*
 NetworkConfigurationPolicyHandler::CreateForUserPolicy() {
   return new NetworkConfigurationPolicyHandler(
-      key::kOpenNetworkConfiguration, onc::ONC_SOURCE_USER_POLICY);
+      key::kOpenNetworkConfiguration,
+      onc::ONC_SOURCE_USER_POLICY,
+      prefs::kOpenNetworkConfiguration);
 }
 
 // static
 NetworkConfigurationPolicyHandler*
 NetworkConfigurationPolicyHandler::CreateForDevicePolicy() {
   return new NetworkConfigurationPolicyHandler(
-      key::kDeviceOpenNetworkConfiguration, onc::ONC_SOURCE_DEVICE_POLICY);
+      key::kDeviceOpenNetworkConfiguration,
+      onc::ONC_SOURCE_DEVICE_POLICY,
+      prefs::kDeviceOpenNetworkConfiguration);
 }
 
 NetworkConfigurationPolicyHandler::~NetworkConfigurationPolicyHandler() {}
@@ -76,12 +80,10 @@
     onc::Validator::Result validation_result;
     root_dict = validator.ValidateAndRepairObject(
         &onc::kToplevelConfigurationSignature, *root_dict, &validation_result);
-    if (validation_result == onc::Validator::VALID_WITH_WARNINGS) {
-      errors->AddError(policy_name(),
-                       IDS_POLICY_NETWORK_CONFIG_IMPORT_PARTIAL);
-    } else if (validation_result == onc::Validator::INVALID) {
+    if (validation_result == onc::Validator::VALID_WITH_WARNINGS)
+      errors->AddError(policy_name(), IDS_POLICY_NETWORK_CONFIG_IMPORT_PARTIAL);
+    else if (validation_result == onc::Validator::INVALID)
       errors->AddError(policy_name(), IDS_POLICY_NETWORK_CONFIG_IMPORT_FAILED);
-    }
 
     // In any case, don't reject the policy as some networks or certificates
     // could still be applied.
@@ -93,8 +95,19 @@
 void NetworkConfigurationPolicyHandler::ApplyPolicySettings(
     const PolicyMap& policies,
     PrefValueMap* prefs) {
-  // Network policy is read directly from the provider and injected into
-  // NetworkLibrary, so no need to convert the policy settings into prefs.
+  const base::Value* value = policies.GetValue(policy_name());
+  if (!value)
+    return;
+
+  std::string onc_blob;
+  value->GetAsString(&onc_blob);
+
+  scoped_ptr<base::ListValue> network_configs(new base::ListValue);
+  base::ListValue certificates;
+  chromeos::onc::ParseAndValidateOncForImport(
+      onc_blob, onc_source_, "", network_configs.get(), &certificates);
+
+  prefs->SetValue(pref_path_, network_configs.release());
 }
 
 void NetworkConfigurationPolicyHandler::PrepareForDisplaying(
@@ -112,9 +125,11 @@
 
 NetworkConfigurationPolicyHandler::NetworkConfigurationPolicyHandler(
     const char* policy_name,
-    chromeos::onc::ONCSource onc_source)
+    chromeos::onc::ONCSource onc_source,
+    const char* pref_path)
     : TypeCheckingPolicyHandler(policy_name, base::Value::TYPE_STRING),
-      onc_source_(onc_source) {
+      onc_source_(onc_source),
+      pref_path_(pref_path) {
 }
 
 // static
diff --git a/chrome/browser/chromeos/policy/configuration_policy_handler_chromeos.h b/chrome/browser/chromeos/policy/configuration_policy_handler_chromeos.h
index 9533d1d..8e0db73 100644
--- a/chrome/browser/chromeos/policy/configuration_policy_handler_chromeos.h
+++ b/chrome/browser/chromeos/policy/configuration_policy_handler_chromeos.h
@@ -36,7 +36,8 @@
  private:
   explicit NetworkConfigurationPolicyHandler(
       const char* policy_name,
-      chromeos::onc::ONCSource onc_source);
+      chromeos::onc::ONCSource onc_source,
+      const char* pref_path);
 
   // Takes network policy in Value representation and produces an output Value
   // that contains a pretty-printed and sanitized version. In particular, we
@@ -48,6 +49,9 @@
   // distinguishes between user and device policy.
   const chromeos::onc::ONCSource onc_source_;
 
+  // The name of the pref to apply the policy to.
+  const char* pref_path_;
+
   DISALLOW_COPY_AND_ASSIGN(NetworkConfigurationPolicyHandler);
 };
 
diff --git a/chrome/browser/chromeos/policy/device_local_account_browsertest.cc b/chrome/browser/chromeos/policy/device_local_account_browsertest.cc
index 3d25797..c5c9a48 100644
--- a/chrome/browser/chromeos/policy/device_local_account_browsertest.cc
+++ b/chrome/browser/chromeos/policy/device_local_account_browsertest.cc
@@ -35,6 +35,7 @@
 #include "chrome/browser/prefs/session_startup_pref.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_finder.h"
+#include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/host_desktop.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/common/chrome_switches.h"
@@ -332,9 +333,10 @@
                                         base::Bind(IsSessionStarted)).Wait();
 
   // Check that the startup pages specified in policy were opened.
-  EXPECT_EQ(1U, chrome::GetTotalBrowserCount());
-  Browser* browser =
-      chrome::FindLastActiveWithHostDesktopType(chrome::HOST_DESKTOP_TYPE_ASH);
+  BrowserList* browser_list =
+    BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH);
+  EXPECT_EQ(1U, browser_list->size());
+  Browser* browser = browser_list->get(0);
   ASSERT_TRUE(browser);
 
   TabStripModel* tabs = browser->tab_strip_model();
diff --git a/chrome/browser/chromeos/policy/network_configuration_updater_impl.cc b/chrome/browser/chromeos/policy/network_configuration_updater_impl.cc
index fae76ac..262e776 100644
--- a/chrome/browser/chromeos/policy/network_configuration_updater_impl.cc
+++ b/chrome/browser/chromeos/policy/network_configuration_updater_impl.cc
@@ -10,6 +10,7 @@
 #include "base/bind_helpers.h"
 #include "base/logging.h"
 #include "base/values.h"
+#include "chrome/browser/chromeos/net/onc_utils.h"
 #include "chrome/browser/policy/policy_map.h"
 #include "chromeos/network/certificate_handler.h"
 #include "chromeos/network/managed_network_configuration_handler.h"
@@ -20,43 +21,96 @@
 namespace policy {
 
 NetworkConfigurationUpdaterImpl::NetworkConfigurationUpdaterImpl(
-    PolicyService* policy_service,
+    PolicyService* device_policy_service,
     scoped_ptr<chromeos::CertificateHandler> certificate_handler)
-    : policy_change_registrar_(
-          policy_service, PolicyNamespace(POLICY_DOMAIN_CHROME, std::string())),
-      policy_service_(policy_service),
+    : device_policy_change_registrar_(device_policy_service,
+                                      PolicyNamespace(POLICY_DOMAIN_CHROME,
+                                                      std::string())),
+      user_policy_service_(NULL),
+      device_policy_service_(device_policy_service),
       certificate_handler_(certificate_handler.Pass()) {
-  policy_change_registrar_.Observe(
+  device_policy_change_registrar_.Observe(
       key::kDeviceOpenNetworkConfiguration,
       base::Bind(&NetworkConfigurationUpdaterImpl::OnPolicyChanged,
                  base::Unretained(this),
                  chromeos::onc::ONC_SOURCE_DEVICE_POLICY));
-  policy_change_registrar_.Observe(
-      key::kOpenNetworkConfiguration,
-      base::Bind(&NetworkConfigurationUpdaterImpl::OnPolicyChanged,
-                 base::Unretained(this),
-                 chromeos::onc::ONC_SOURCE_USER_POLICY));
 
-  // Apply the current device policies immediately.
-  ApplyNetworkConfiguration(chromeos::onc::ONC_SOURCE_DEVICE_POLICY);
+  if (device_policy_service_->IsInitializationComplete(POLICY_DOMAIN_CHROME)) {
+    // Apply the current device policies immediately.
+    VLOG(1) << "Device policy service is already initialized.";
+    ApplyNetworkConfiguration(chromeos::onc::ONC_SOURCE_DEVICE_POLICY);
+  } else {
+    device_policy_service_->AddObserver(POLICY_DOMAIN_CHROME, this);
+  }
 }
 
 NetworkConfigurationUpdaterImpl::~NetworkConfigurationUpdaterImpl() {
+  DCHECK(!user_policy_service_);
+  DCHECK(!user_policy_change_registrar_);
+  device_policy_service_->RemoveObserver(POLICY_DOMAIN_CHROME, this);
 }
 
 void NetworkConfigurationUpdaterImpl::SetUserPolicyService(
     bool allow_trusted_certs_from_policy,
     const std::string& hashed_username,
     PolicyService* user_policy_service) {
-  // TODO(pneubeck): observe user_policy_service for the actual initialization.
-  VLOG(1) << "User policy initialized.";
+  VLOG(1) << "Got user policy service.";
+  user_policy_service_ = user_policy_service;
   hashed_username_ = hashed_username;
   if (allow_trusted_certs_from_policy)
     SetAllowTrustedCertsFromPolicy();
-  ApplyNetworkConfiguration(chromeos::onc::ONC_SOURCE_USER_POLICY);
+
+  user_policy_change_registrar_.reset(new PolicyChangeRegistrar(
+      user_policy_service_,
+      PolicyNamespace(POLICY_DOMAIN_CHROME, std::string())));
+  user_policy_change_registrar_->Observe(
+      key::kOpenNetworkConfiguration,
+      base::Bind(&NetworkConfigurationUpdaterImpl::OnPolicyChanged,
+                 base::Unretained(this),
+                 chromeos::onc::ONC_SOURCE_USER_POLICY));
+
+  if (user_policy_service_->IsInitializationComplete(POLICY_DOMAIN_CHROME)) {
+    VLOG(1) << "User policy service is already initialized.";
+    ApplyNetworkConfiguration(chromeos::onc::ONC_SOURCE_USER_POLICY);
+  } else {
+    user_policy_service_->AddObserver(POLICY_DOMAIN_CHROME, this);
+  }
 }
 
 void NetworkConfigurationUpdaterImpl::UnsetUserPolicyService() {
+  if (!user_policy_service_)
+    return;
+
+  user_policy_change_registrar_.reset();
+  user_policy_service_->RemoveObserver(POLICY_DOMAIN_CHROME, this);
+  user_policy_service_ = NULL;
+}
+
+void NetworkConfigurationUpdaterImpl::OnPolicyUpdated(
+    const PolicyNamespace& ns,
+    const PolicyMap& previous,
+    const PolicyMap& current) {
+  // Ignore this call. Policy changes are already observed by the registrar.
+}
+
+void NetworkConfigurationUpdaterImpl::OnPolicyServiceInitialized(
+    PolicyDomain domain) {
+  if (domain != POLICY_DOMAIN_CHROME)
+    return;
+
+  // We don't know which policy service called this function, thus check
+  // both. Multiple removes are handled gracefully.
+  if (device_policy_service_->IsInitializationComplete(POLICY_DOMAIN_CHROME)) {
+    VLOG(1) << "Device policy service initialized.";
+    device_policy_service_->RemoveObserver(POLICY_DOMAIN_CHROME, this);
+    ApplyNetworkConfiguration(chromeos::onc::ONC_SOURCE_DEVICE_POLICY);
+  }
+  if (user_policy_service_ &&
+      user_policy_service_->IsInitializationComplete(POLICY_DOMAIN_CHROME)) {
+    VLOG(1) << "User policy service initialized.";
+    user_policy_service_->RemoveObserver(POLICY_DOMAIN_CHROME, this);
+    ApplyNetworkConfiguration(chromeos::onc::ONC_SOURCE_USER_POLICY);
+  }
 }
 
 void NetworkConfigurationUpdaterImpl::OnPolicyChanged(
@@ -74,12 +128,16 @@
           << chromeos::onc::GetSourceAsString(onc_source);
 
   std::string policy_key;
-  if (onc_source == chromeos::onc::ONC_SOURCE_USER_POLICY)
+  PolicyService* policy_service;
+  if (onc_source == chromeos::onc::ONC_SOURCE_USER_POLICY) {
     policy_key = key::kOpenNetworkConfiguration;
-  else
+    policy_service = user_policy_service_;
+  } else {
     policy_key = key::kDeviceOpenNetworkConfiguration;
+    policy_service = device_policy_service_;
+  }
 
-  const PolicyMap& policies = policy_service_->GetPolicies(
+  const PolicyMap& policies = policy_service->GetPolicies(
       PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()));
   const base::Value* policy_value = policies.GetValue(policy_key);
 
@@ -97,21 +155,17 @@
   chromeos::onc::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);
+      certificates, onc_source, web_trust_certs.get());
 
-  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;
+  if (onc_source == chromeos::onc::ONC_SOURCE_USER_POLICY) {
+    userhash = hashed_username_;
+    chromeos::onc::ExpandStringPlaceholdersInNetworksForUser(hashed_username_,
+                                                             &network_configs);
   }
 
-  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);
 
diff --git a/chrome/browser/chromeos/policy/network_configuration_updater_impl.h b/chrome/browser/chromeos/policy/network_configuration_updater_impl.h
index 955aaa4..f9d7f10 100644
--- a/chrome/browser/chromeos/policy/network_configuration_updater_impl.h
+++ b/chrome/browser/chromeos/policy/network_configuration_updater_impl.h
@@ -15,7 +15,6 @@
 
 namespace chromeos {
 class CertificateHandler;
-class ManagedNetworkConfigurationHandler;
 }
 
 namespace policy {
@@ -25,10 +24,11 @@
 // This implementation pushes policies to the
 // ManagedNetworkConfigurationHandler. User policies are only pushed after
 // OnUserPolicyInitialized() was called.
-class NetworkConfigurationUpdaterImpl : public NetworkConfigurationUpdater {
+class NetworkConfigurationUpdaterImpl : public NetworkConfigurationUpdater,
+                                        public PolicyService::Observer {
  public:
   NetworkConfigurationUpdaterImpl(
-      PolicyService* policy_service,
+      PolicyService* device_policy_service,
       scoped_ptr<chromeos::CertificateHandler> certificate_handler);
   virtual ~NetworkConfigurationUpdaterImpl();
 
@@ -40,27 +40,38 @@
 
   virtual void UnsetUserPolicyService() OVERRIDE;
 
- private:
-  // Callback that's called by |policy_service_| if the respective ONC policy
-  // changed.
-  void OnPolicyChanged(chromeos::onc::ONCSource onc_source,
-                       const base::Value* previous,
-                       const base::Value* current);
+  // PolicyService::Observer overrides for both device and user policies.
+  virtual void OnPolicyUpdated(const PolicyNamespace& ns,
+                               const PolicyMap& previous,
+                               const PolicyMap& current) OVERRIDE;
+  virtual void OnPolicyServiceInitialized(PolicyDomain domain) OVERRIDE;
 
-  void ApplyNetworkConfiguration(chromeos::onc::ONCSource onc_source);
+  private:
+   // Called if the ONC policy from |onc_source| changed.
+   void OnPolicyChanged(chromeos::onc::ONCSource onc_source,
+                        const base::Value* previous,
+                        const base::Value* current);
 
-  // Wraps the policy service we read network configuration from.
-  PolicyChangeRegistrar policy_change_registrar_;
+   void ApplyNetworkConfiguration(chromeos::onc::ONCSource onc_source);
 
-  // The policy service storing the ONC policies.
-  PolicyService* policy_service_;
+   // Used to register for notifications from the |user_policy_service_|.
+   scoped_ptr<PolicyChangeRegistrar> user_policy_change_registrar_;
 
-  // User hash of the user that the user policy applies to.
-  std::string hashed_username_;
+   // Used to register for notifications from the |device_policy_service_|.
+   PolicyChangeRegistrar device_policy_change_registrar_;
 
-  scoped_ptr<chromeos::CertificateHandler> certificate_handler_;
+   // Used to retrieve user policies.
+   PolicyService* user_policy_service_;
 
-  DISALLOW_COPY_AND_ASSIGN(NetworkConfigurationUpdaterImpl);
+   // Used to retrieve device policies.
+   PolicyService* device_policy_service_;
+
+   // User hash of the user that the user policy applies to.
+   std::string hashed_username_;
+
+   scoped_ptr<chromeos::CertificateHandler> certificate_handler_;
+
+   DISALLOW_COPY_AND_ASSIGN(NetworkConfigurationUpdaterImpl);
 };
 
 }  // namespace policy
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 654382e..95de6fb 100644
--- a/chrome/browser/chromeos/policy/network_configuration_updater_impl_cros.cc
+++ b/chrome/browser/chromeos/policy/network_configuration_updater_impl_cros.cc
@@ -165,18 +165,9 @@
   chromeos::onc::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.";
-  }
+      certificates, onc_source, web_trust_certs.get());
 
   network_library_->LoadOncNetworks(network_configs, onc_source);
 
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 292dcd7..1bd6eb9 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
@@ -25,7 +25,6 @@
 #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"
@@ -183,7 +182,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(),
@@ -201,16 +200,10 @@
       onc::ONC_SOURCE_USER_POLICY));
   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(_));
 
@@ -254,7 +247,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(),
@@ -268,12 +261,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(_));
 
@@ -298,7 +291,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(),
@@ -321,11 +314,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.
@@ -355,7 +348,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(),
@@ -369,7 +362,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(
@@ -378,7 +371,7 @@
   EXPECT_CALL(*certificate_handler, ImportCertificates(
       IsEqualTo(empty_certificates_.get()),
       Ne(NameToONCSource(GetParam())),
-      _, _));
+      _));
 
   PolicyMap policy;
   policy.Set(GetParam(), POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
@@ -395,7 +388,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()),
@@ -403,7 +396,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/power/power_prefs.cc b/chrome/browser/chromeos/power/power_prefs.cc
index 60fc213..c2081bb 100644
--- a/chrome/browser/chromeos/power/power_prefs.cc
+++ b/chrome/browser/chromeos/power/power_prefs.cc
@@ -10,6 +10,7 @@
 #include "base/logging.h"
 #include "base/prefs/pref_change_registrar.h"
 #include "base/prefs/pref_service.h"
+#include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/profiles/profile.h"
@@ -74,10 +75,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());
+      ProfileManager* profile_manager = g_browser_process->profile_manager();
+      if (!profile_manager || !profile_manager->IsLoggedIn())
+        SetProfile(ProfileHelper::GetSigninProfile());
       break;
+    }
     case chrome::NOTIFICATION_SESSION_STARTED:
       // Update |profile_| when entering a session.
       SetProfile(ProfileManager::GetDefaultProfile());
diff --git a/chrome/browser/chromeos/power/power_prefs_unittest.cc b/chrome/browser/chromeos/power/power_prefs_unittest.cc
index 27deca2..e5cd2d3 100644
--- a/chrome/browser/chromeos/power/power_prefs_unittest.cc
+++ b/chrome/browser/chromeos/power/power_prefs_unittest.cc
@@ -235,6 +235,18 @@
   EXPECT_EQ(GetExpectedAllowScreenWakeLocksForProfile(user_profile),
             GetCurrentAllowScreenWakeLocks());
 
+  // Simulate the login screen coming up as part of screen locking.
+  power_prefs_->Observe(chrome::NOTIFICATION_LOGIN_WEBUI_VISIBLE,
+                        content::Source<PowerPrefsTest>(this),
+                        content::NotificationService::NoDetails());
+
+  // Verify that power policy didn't revert to login screen settings.
+  EXPECT_EQ(user_profile, GetProfile());
+  EXPECT_EQ(GetExpectedPowerPolicyForProfile(user_profile),
+            GetCurrentPowerPolicy());
+  EXPECT_EQ(GetExpectedAllowScreenWakeLocksForProfile(user_profile),
+            GetCurrentAllowScreenWakeLocks());
+
   // Inform power_prefs_ that the session has ended and the user profile has
   // been destroyed.
   power_prefs_->Observe(chrome::NOTIFICATION_PROFILE_DESTROYED,
diff --git a/chrome/browser/chromeos/preferences.cc b/chrome/browser/chromeos/preferences.cc
index 5248353..3925818 100644
--- a/chrome/browser/chromeos/preferences.cc
+++ b/chrome/browser/chromeos/preferences.cc
@@ -33,7 +33,7 @@
 #include "chromeos/ime/input_method_manager.h"
 #include "chromeos/ime/xkeyboard.h"
 #include "components/user_prefs/pref_registry_syncable.h"
-#include "third_party/icu/public/i18n/unicode/timezone.h"
+#include "third_party/icu/source/i18n/unicode/timezone.h"
 #include "ui/base/events/event_constants.h"
 #include "ui/base/events/event_utils.h"
 #include "url/gurl.h"
diff --git a/chrome/browser/chromeos/proxy_config_service_impl.cc b/chrome/browser/chromeos/proxy_config_service_impl.cc
index 95f4f19..7c618f8 100644
--- a/chrome/browser/chromeos/proxy_config_service_impl.cc
+++ b/chrome/browser/chromeos/proxy_config_service_impl.cc
@@ -5,6 +5,8 @@
 #include "chrome/browser/chromeos/proxy_config_service_impl.h"
 
 #include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/callback.h"
 #include "base/location.h"
 #include "base/logging.h"
 #include "base/prefs/pref_service.h"
@@ -27,12 +29,17 @@
 
 namespace {
 
-// Writes the proxy config of |network| to |proxy_config|.  Returns false if no
+// Writes the proxy config of |network| to |proxy_config|.  Set |onc_source| to
+// the source of this configuration. Returns false if no
 // proxy was configured for this network.
-bool GetProxyConfig(const NetworkState& network,
-                    net::ProxyConfig* proxy_config) {
+bool GetProxyConfig(const PrefService* profile_prefs,
+                    const PrefService* local_state_prefs,
+                    const NetworkState& network,
+                    net::ProxyConfig* proxy_config,
+                    onc::ONCSource* onc_source) {
   scoped_ptr<ProxyConfigDictionary> proxy_dict =
-      proxy_config::GetProxyConfigForNetwork(network);
+      proxy_config::GetProxyConfigForNetwork(
+          profile_prefs, local_state_prefs, network, onc_source);
   if (!proxy_dict)
     return false;
   return PrefProxyConfigTrackerImpl::PrefConfigToNetConfig(*proxy_dict,
@@ -47,16 +54,21 @@
                                                : local_state_prefs),
       active_config_state_(ProxyPrefs::CONFIG_UNSET),
       profile_prefs_(profile_prefs),
+      local_state_prefs_(local_state_prefs),
       pointer_factory_(this) {
-  // Register for notifications of UseSharedProxies user preference.
+  const base::Closure proxy_change_callback = base::Bind(
+      &ProxyConfigServiceImpl::OnProxyPrefChanged, base::Unretained(this));
+
   if (profile_prefs) {
-    DCHECK(profile_prefs->FindPreference(prefs::kUseSharedProxies));
-    use_shared_proxies_.Init(
-        prefs::kUseSharedProxies,
-        profile_prefs,
-        base::Bind(&ProxyConfigServiceImpl::OnUseSharedProxiesChanged,
-                   base::Unretained(this)));
+    profile_pref_registrar_.Init(profile_prefs);
+    profile_pref_registrar_.Add(prefs::kOpenNetworkConfiguration,
+                                proxy_change_callback);
+    profile_pref_registrar_.Add(prefs::kUseSharedProxies,
+                                proxy_change_callback);
   }
+  local_state_pref_registrar_.Init(local_state_prefs);
+  local_state_pref_registrar_.Add(prefs::kDeviceOpenNetworkConfiguration,
+                                  proxy_change_callback);
 
   // Register for changes to the default network.
   NetworkStateHandler* state_handler =
@@ -81,8 +93,7 @@
   DetermineEffectiveConfigFromDefaultNetwork();
 }
 
-void ProxyConfigServiceImpl::OnUseSharedProxiesChanged() {
-  VLOG(1) << "use-shared-proxies pref changed.";
+void ProxyConfigServiceImpl::OnProxyPrefChanged() {
   DetermineEffectiveConfigFromDefaultNetwork();
 }
 
@@ -116,9 +127,11 @@
     return false;
   }
 
-  const NetworkProfile* profile =
-      NetworkHandler::Get()->network_profile_handler()->
-      GetProfileForPath(network_profile_path);
+  if (network_profile_path.empty())
+    return true;
+
+  const NetworkProfile* profile = NetworkHandler::Get()
+      ->network_profile_handler()->GetProfileForPath(network_profile_path);
   if (!profile) {
     LOG(WARNING) << "Unknown profile_path '" << network_profile_path
                  << "'. Ignoring proxy.";
@@ -133,7 +146,7 @@
         g_browser_process->browser_policy_connector();
     const User* logged_in_user = UserManager::Get()->GetLoggedInUser();
     if (connector->GetUserAffiliation(logged_in_user->email()) ==
-            policy::USER_AFFILIATION_MANAGED) {
+        policy::USER_AFFILIATION_MANAGED) {
       VLOG(1) << "Respecting proxy for network, as logged-in user belongs to "
               << "the domain the device is enrolled to.";
       return false;
@@ -160,16 +173,19 @@
       net::ProxyConfigService::CONFIG_UNSET;
   bool ignore_proxy = true;
   if (network) {
-    ignore_proxy = IgnoreProxy(
-        profile_prefs_, network->profile_path(), network->onc_source());
+    onc::ONCSource onc_source = onc::ONC_SOURCE_NONE;
+    const bool network_proxy_configured = chromeos::GetProxyConfig(
+        prefs(), local_state_prefs_, *network, &network_config, &onc_source);
+    ignore_proxy =
+        IgnoreProxy(profile_prefs_, network->profile_path(), onc_source);
+
     // If network is shared but use-shared-proxies is off, use direct mode.
     if (ignore_proxy) {
-      VLOG(1) << "Shared network && !use-shared-proxies, use direct";
+      network_config = net::ProxyConfig();
       network_availability = net::ProxyConfigService::CONFIG_VALID;
-    } else if (chromeos::GetProxyConfig(*network, &network_config)) {
+    } else if (network_proxy_configured) {
       // Network is private or shared with user using shared proxies.
-      VLOG(1) << this << ": using network proxy: "
-              << network->proxy_config();
+      VLOG(1) << this << ": using proxy of network " << network->path();
       network_availability = net::ProxyConfigService::CONFIG_VALID;
     }
   }
@@ -186,8 +202,8 @@
   bool update_now = update_pending();
   if (!update_now) {  // Otherwise, only update now if there're changes.
     update_now = active_config_state_ != effective_config_state ||
-        (active_config_state_ != ProxyPrefs::CONFIG_UNSET &&
-         !active_config_.Equals(effective_config));
+                 (active_config_state_ != ProxyPrefs::CONFIG_UNSET &&
+                  !active_config_.Equals(effective_config));
   }
   if (update_now) {  // Activate and store new effective config.
     active_config_state_ = effective_config_state;
@@ -201,13 +217,13 @@
       effective_config_state = ProxyPrefs::CONFIG_OTHER_PRECEDE;
     // If config is manual, add rule to bypass local host.
     if (effective_config.proxy_rules().type !=
-        net::ProxyConfig::ProxyRules::TYPE_NO_RULES)
+        net::ProxyConfig::ProxyRules::TYPE_NO_RULES) {
       effective_config.proxy_rules().bypass_rules.AddRuleToBypassLocal();
+    }
     PrefProxyConfigTrackerImpl::OnProxyConfigChanged(effective_config_state,
                                                      effective_config);
     if (VLOG_IS_ON(1) && !update_pending()) {  // Update was successful.
-      scoped_ptr<base::DictionaryValue> config_dict(
-          effective_config.ToValue());
+      scoped_ptr<base::DictionaryValue> config_dict(effective_config.ToValue());
       VLOG(1) << this << ": Proxy changed: "
               << ProxyPrefs::ConfigStateToDebugString(active_config_state_)
               << ", " << *config_dict;
diff --git a/chrome/browser/chromeos/proxy_config_service_impl.h b/chrome/browser/chromeos/proxy_config_service_impl.h
index de8f493..1037a05 100644
--- a/chrome/browser/chromeos/proxy_config_service_impl.h
+++ b/chrome/browser/chromeos/proxy_config_service_impl.h
@@ -9,17 +9,11 @@
 
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
-#include "base/prefs/pref_member.h"
+#include "base/prefs/pref_change_registrar.h"
 #include "chrome/browser/net/pref_proxy_config_tracker_impl.h"
 #include "chromeos/network/network_state_handler_observer.h"
 #include "chromeos/network/onc/onc_constants.h"
 
-class PrefRegistrySimple;
-
-namespace user_prefs {
-class PrefRegistrySyncable;
-}
-
 namespace chromeos {
 
 class NetworkState;
@@ -70,8 +64,8 @@
                           onc::ONCSource onc_source);
 
  private:
-  // Called when the kUseSharedProxies preference changes.
-  void OnUseSharedProxiesChanged();
+  // Called when any proxy preference changes.
+  void OnProxyPrefChanged();
 
   // Determines effective proxy config based on prefs from config tracker, the
   // current default network and if user is using shared proxies.  The effective
@@ -86,13 +80,20 @@
   // Active proxy configuration, which could be from prefs or network.
   net::ProxyConfig active_config_;
 
-  // Track changes in UseSharedProxies user preference.
-  BooleanPrefMember use_shared_proxies_;
+  // Track changes in profile preferences: UseSharedProxies and
+  // OpenNetworkConfiguration.
+  PrefChangeRegistrar profile_pref_registrar_;
+
+  // Track changes in local state preferences: DeviceOpenNetworkConfiguration.
+  PrefChangeRegistrar local_state_pref_registrar_;
 
   // Not owned. NULL if tracking only local state prefs (e.g. in the system
   // request context or sign-in screen).
   PrefService* profile_prefs_;
 
+  // Not owned.
+  PrefService* local_state_prefs_;
+
   base::WeakPtrFactory<ProxyConfigServiceImpl> pointer_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(ProxyConfigServiceImpl);
diff --git a/chrome/browser/chromeos/proxy_config_service_impl_unittest.cc b/chrome/browser/chromeos/proxy_config_service_impl_unittest.cc
index a0dea43..f66a0b5 100644
--- a/chrome/browser/chromeos/proxy_config_service_impl_unittest.cc
+++ b/chrome/browser/chromeos/proxy_config_service_impl_unittest.cc
@@ -221,14 +221,16 @@
     SetUpNetwork();
 
     PrefProxyConfigTrackerImpl::RegisterPrefs(pref_service_.registry());
-    proxy_config_service_.reset(new ChromeProxyConfigService(NULL));
+
     // Create a ProxyConfigServiceImpl like for the system request context.
     config_service_impl_.reset(
         new ProxyConfigServiceImpl(NULL,  // no profile prefs
                                    &pref_service_));
-    config_service_impl_->SetChromeProxyConfigService(
-        proxy_config_service_.get());
-    // SetChromeProxyConfigService triggers update of initial prefs proxy
+    proxy_config_service_ =
+        config_service_impl_->CreateTrackingProxyConfigService(
+            scoped_ptr<net::ProxyConfigService>());
+
+    // CreateTrackingProxyConfigService triggers update of initial prefs proxy
     // config by tracker to chrome proxy config service, so flush all pending
     // tasks so that tests start fresh.
     loop_.RunUntilIdle();
@@ -319,7 +321,7 @@
   }
 
   base::MessageLoop loop_;
-  scoped_ptr<ChromeProxyConfigService> proxy_config_service_;
+  scoped_ptr<net::ProxyConfigService> proxy_config_service_;
   scoped_ptr<ProxyConfigServiceImpl> config_service_impl_;
   TestingPrefServiceSimple pref_service_;
 
diff --git a/chrome/browser/chromeos/proxy_cros_settings_parser.cc b/chrome/browser/chromeos/proxy_cros_settings_parser.cc
index a6195d9..2ccb83d 100644
--- a/chrome/browser/chromeos/proxy_cros_settings_parser.cc
+++ b/chrome/browser/chromeos/proxy_cros_settings_parser.cc
@@ -366,7 +366,8 @@
     data = new base::StringValue("");
   dict->Set("value", data);
   if (path == kProxyType) {
-    dict->SetString("controlledBy", controlled_by);
+    if (!controlled_by.empty())
+      dict->SetString("controlledBy", controlled_by);
     dict->SetBoolean("disabled", !config.user_modifiable);
   } else {
     dict->SetBoolean("disabled", false);
diff --git a/chrome/browser/chromeos/settings/device_oauth2_token_service.cc b/chrome/browser/chromeos/settings/device_oauth2_token_service.cc
index 361d49e..58d823d 100644
--- a/chrome/browser/chromeos/settings/device_oauth2_token_service.cc
+++ b/chrome/browser/chromeos/settings/device_oauth2_token_service.cc
@@ -195,10 +195,10 @@
 DeviceOAuth2TokenService::DeviceOAuth2TokenService(
     net::URLRequestContextGetter* getter,
     PrefService* local_state)
-    : OAuth2TokenService(getter),
-      refresh_token_is_valid_(false),
+    : refresh_token_is_valid_(false),
       max_refresh_token_validation_retries_(3),
       pending_validators_(new std::set<ValidatingConsumer*>()),
+      url_request_context_getter_(getter),
       local_state_(local_state) {
 }
 
@@ -206,6 +206,11 @@
   STLDeleteElements(pending_validators_.get());
 }
 
+net::URLRequestContextGetter* DeviceOAuth2TokenService::GetRequestContext() {
+  return url_request_context_getter_.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
diff --git a/chrome/browser/chromeos/settings/device_oauth2_token_service.h b/chrome/browser/chromeos/settings/device_oauth2_token_service.h
index 9ace020..c509216 100644
--- a/chrome/browser/chromeos/settings/device_oauth2_token_service.h
+++ b/chrome/browser/chromeos/settings/device_oauth2_token_service.h
@@ -66,6 +66,9 @@
                                     PrefService* local_state);
   virtual ~DeviceOAuth2TokenService();
 
+  // Implementation of OAuth2TokenService.
+  virtual net::URLRequestContextGetter* GetRequestContext() OVERRIDE;
+
   void OnValidationComplete(ValidatingConsumer* validator, bool token_is_valid);
 
   bool refresh_token_is_valid_;
@@ -73,6 +76,8 @@
 
   scoped_ptr<std::set<ValidatingConsumer*> > pending_validators_;
 
+  scoped_refptr<net::URLRequestContextGetter> url_request_context_getter_;
+
   // Cache the decrypted refresh token, so we only decrypt once.
   std::string refresh_token_;
   PrefService* local_state_;
diff --git a/chrome/browser/chromeos/settings/system_settings_provider.h b/chrome/browser/chromeos/settings/system_settings_provider.h
index ef7c174..0b993b1 100644
--- a/chrome/browser/chromeos/settings/system_settings_provider.h
+++ b/chrome/browser/chromeos/settings/system_settings_provider.h
@@ -11,7 +11,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "chrome/browser/chromeos/settings/cros_settings_provider.h"
 #include "chrome/browser/chromeos/system/timezone_settings.h"
-#include "third_party/icu/public/i18n/unicode/timezone.h"
+#include "third_party/icu/source/i18n/unicode/timezone.h"
 
 namespace base {
 class StringValue;
diff --git a/chrome/browser/chromeos/system/ash_system_tray_delegate.cc b/chrome/browser/chromeos/system/ash_system_tray_delegate.cc
index 4d6b796..8c2fdb4 100644
--- a/chrome/browser/chromeos/system/ash_system_tray_delegate.cc
+++ b/chrome/browser/chromeos/system/ash_system_tray_delegate.cc
@@ -542,14 +542,14 @@
     if (!active_contents)
       return true;
 
-    GURL active_url = active_contents->GetActiveURL();
+    GURL visible_url = active_contents->GetLastCommittedURL();
     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);
+    return (visible_url.spec() != display_settings_url) &&
+        (visible_url.spec() != display_overscan_url);
   }
 
   virtual void ShowDriveSettings() OVERRIDE {
diff --git a/chrome/browser/chromeos/system/input_device_settings.cc b/chrome/browser/chromeos/system/input_device_settings.cc
index 91471f0..09c17ae 100644
--- a/chrome/browser/chromeos/system/input_device_settings.cc
+++ b/chrome/browser/chromeos/system/input_device_settings.cc
@@ -64,8 +64,14 @@
   }
   va_end(vl);
 
-  content::BrowserThread::GetBlockingPool()->PostTask(FROM_HERE,
-      base::Bind(&ExecuteScriptOnFileThread, argv));
+  // Control scripts can take long enough to cause SIGART during shutdown
+  // (http://crbug.com/261426). Run the blocking pool task with
+  // CONTINUE_ON_SHUTDOWN so it won't be joined when Chrome shuts down.
+  base::SequencedWorkerPool* pool = content::BrowserThread::GetBlockingPool();
+  scoped_refptr<base::TaskRunner> runner =
+      pool->GetTaskRunnerWithShutdownBehavior(
+          base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN);
+  runner->PostTask(FROM_HERE, base::Bind(&ExecuteScriptOnFileThread, argv));
 }
 
 void SetPointerSensitivity(const char* script, int value) {
diff --git a/chrome/browser/chromeos/system/timezone_settings.cc b/chrome/browser/chromeos/system/timezone_settings.cc
index 6ebffc9..eab34e9 100644
--- a/chrome/browser/chromeos/system/timezone_settings.cc
+++ b/chrome/browser/chromeos/system/timezone_settings.cc
@@ -21,7 +21,7 @@
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/render_widget_host.h"
-#include "third_party/icu/public/i18n/unicode/timezone.h"
+#include "third_party/icu/source/i18n/unicode/timezone.h"
 
 using content::BrowserThread;
 
diff --git a/chrome/browser/chromeos/system/timezone_settings.h b/chrome/browser/chromeos/system/timezone_settings.h
index 6e9cc6c..ca62bf9 100644
--- a/chrome/browser/chromeos/system/timezone_settings.h
+++ b/chrome/browser/chromeos/system/timezone_settings.h
@@ -8,7 +8,7 @@
 #include <vector>
 
 #include "base/strings/string16.h"
-#include "third_party/icu/public/i18n/unicode/timezone.h"
+#include "third_party/icu/source/i18n/unicode/timezone.h"
 
 namespace chromeos {
 namespace system {
diff --git a/chrome/browser/chromeos/ui_proxy_config_service.cc b/chrome/browser/chromeos/ui_proxy_config_service.cc
index a7925a9..d607c0e 100644
--- a/chrome/browser/chromeos/ui_proxy_config_service.cc
+++ b/chrome/browser/chromeos/ui_proxy_config_service.cc
@@ -35,51 +35,57 @@
   return "";
 }
 
-// Writes the proxy config of |network| to |proxy_config|.  Returns false if no
-// proxy was configured for this network.
-bool GetProxyConfig(const NetworkState& network,
-                    net::ProxyConfig* proxy_config) {
+// Writes the proxy config of |network| to |proxy_config|.  Sets |onc_source| to
+// the source of this configuration. Returns false if no proxy was configured
+// for this network.
+bool GetProxyConfig(const PrefService* profile_prefs,
+                    const PrefService* local_state_prefs,
+                    const NetworkState& network,
+                    net::ProxyConfig* proxy_config,
+                    onc::ONCSource* onc_source) {
   scoped_ptr<ProxyConfigDictionary> proxy_dict =
-      proxy_config::GetProxyConfigForNetwork(network);
+      proxy_config::GetProxyConfigForNetwork(
+          profile_prefs, local_state_prefs, network, onc_source);
   if (!proxy_dict)
     return false;
   return PrefProxyConfigTrackerImpl::PrefConfigToNetConfig(*proxy_dict,
                                                            proxy_config);
 }
 
-// Returns true if proxy settings of |network| are editable.
-bool IsNetworkProxySettingsEditable(const NetworkState& network) {
-  onc::ONCSource source = network.onc_source();
-  return source != onc::ONC_SOURCE_DEVICE_POLICY &&
-      source != onc::ONC_SOURCE_USER_POLICY;
+// Returns true if proxy settings from |onc_source| are editable.
+bool IsNetworkProxySettingsEditable(const onc::ONCSource onc_source) {
+  return onc_source != onc::ONC_SOURCE_DEVICE_POLICY &&
+         onc_source != onc::ONC_SOURCE_USER_POLICY;
 }
 
 }  // namespace
 
 UIProxyConfigService::UIProxyConfigService()
-    : signin_screen_(false),
-      pref_service_(NULL) {
+    : profile_prefs_(NULL), local_state_prefs_(NULL) {
 }
 
 UIProxyConfigService::~UIProxyConfigService() {
 }
 
-void UIProxyConfigService::SetPrefs(bool signin_screen,
-                                    PrefService* pref_service) {
-  signin_screen_ = signin_screen;
-  pref_service_ = pref_service;
+void UIProxyConfigService::SetPrefs(PrefService* profile_prefs,
+                                    PrefService* local_state_prefs) {
+  profile_prefs_ = profile_prefs;
+  local_state_prefs_ = local_state_prefs;
 }
 
 void UIProxyConfigService::SetCurrentNetwork(
     const std::string& current_network) {
-  const NetworkState* network = NULL;
-  if (!current_network.empty()) {
-    network = NetworkHandler::Get()->network_state_handler()->GetNetworkState(
-        current_network);
-    LOG_IF(ERROR, !network)
-        << "Can't find requested network " << current_network;
-  }
   current_ui_network_ = current_network;
+}
+
+void UIProxyConfigService::UpdateFromPrefs() {
+  const NetworkState* network = NULL;
+  if (!current_ui_network_.empty()) {
+    network = NetworkHandler::Get()->network_state_handler()
+        ->GetNetworkState(current_ui_network_);
+    LOG_IF(ERROR, !network) << "Can't find requested network "
+                            << current_ui_network_;
+  }
   if (!network) {
     current_ui_network_.clear();
     current_ui_config_ = UIProxyConfig();
@@ -87,9 +93,8 @@
   }
 
   DetermineEffectiveConfig(*network);
-  VLOG(1) << "Current ui network: "
-          << network->name()
-          << ", " << ModeToString(current_ui_config_.mode) << ", "
+  VLOG(1) << "Current ui network: " << network->name() << ", "
+          << ModeToString(current_ui_config_.mode) << ", "
           << ProxyPrefs::ConfigStateToDebugString(current_ui_config_.state)
           << ", modifiable:" << current_ui_config_.user_modifiable;
 }
@@ -125,20 +130,30 @@
 
 void UIProxyConfigService::DetermineEffectiveConfig(
     const NetworkState& network) {
-  DCHECK(pref_service_);
+  DCHECK(local_state_prefs_);
+
+  // The pref service to read proxy settings that apply to all networks.
+  // Settings from the profile overrule local state.
+  PrefService* top_pref_service =
+      profile_prefs_ ? profile_prefs_ : local_state_prefs_;
 
   // Get prefs proxy config if available.
   net::ProxyConfig pref_config;
   ProxyPrefs::ConfigState pref_state = ProxyConfigServiceImpl::ReadPrefConfig(
-      pref_service_, &pref_config);
+      top_pref_service, &pref_config);
 
   // Get network proxy config if available.
   net::ProxyConfig network_config;
   net::ProxyConfigService::ConfigAvailability network_availability =
       net::ProxyConfigService::CONFIG_UNSET;
-  if (chromeos::GetProxyConfig(network, &network_config)) {
+  onc::ONCSource onc_source = onc::ONC_SOURCE_NONE;
+  if (chromeos::GetProxyConfig(profile_prefs_,
+                               local_state_prefs_,
+                               network,
+                               &network_config,
+                               &onc_source)) {
     // Network is private or shared with user using shared proxies.
-    VLOG(1) << this << ": using network proxy: " << network.proxy_config();
+    VLOG(1) << this << ": using proxy of network: " << network.path();
     network_availability = net::ProxyConfigService::CONFIG_VALID;
   }
 
@@ -155,16 +170,12 @@
   current_ui_config_.state = effective_config_state;
   if (ProxyConfigServiceImpl::PrefPrecedes(effective_config_state)) {
     current_ui_config_.user_modifiable = false;
-  } else if (!IsNetworkProxySettingsEditable(network)) {
-    // TODO(xiyuan): Figure out the right way to set config state for managed
-    // network.
+  } else if (!IsNetworkProxySettingsEditable(onc_source)) {
     current_ui_config_.state = ProxyPrefs::CONFIG_POLICY;
     current_ui_config_.user_modifiable = false;
   } else {
     current_ui_config_.user_modifiable = !ProxyConfigServiceImpl::IgnoreProxy(
-        signin_screen_ ? NULL : pref_service_,
-        network.profile_path(),
-        network.onc_source());
+        profile_prefs_, network.profile_path(), onc_source);
   }
 }
 
diff --git a/chrome/browser/chromeos/ui_proxy_config_service.h b/chrome/browser/chromeos/ui_proxy_config_service.h
index f9d0de3..c6e28bb 100644
--- a/chrome/browser/chromeos/ui_proxy_config_service.h
+++ b/chrome/browser/chromeos/ui_proxy_config_service.h
@@ -28,19 +28,19 @@
   UIProxyConfigService();
   ~UIProxyConfigService();
 
-  // |signin_screen| indicates whether this object is used for the
-  // signin screen, in which case proxies of (shared) networks are
-  // unconditionally respected. After signin, proxy settings of shared networks
-  // may be ignored, e.g. depending on the kUseSharedProxies flag. After this
-  // call, proxy settings are read from
-  // |prefs|.
-  void SetPrefs(bool signin_screen, PrefService* prefs);
+  // After this call, proxy settings are read from |profile_prefs| and
+  // |local_state_prefs|. In case of usage for the sign-in screen,
+  // |profile_prefs| must be NULL because sign-in screen should depend only on
+  // shared settings.
+  void SetPrefs(PrefService* profile_prefs, PrefService* local_state_prefs);
 
   // Called by UI to set the network with service path |current_network| to be
   // displayed or edited.  Subsequent Set*/Get* methods will use this
   // network, until this method is called again.
   void SetCurrentNetwork(const std::string& current_network);
 
+  void UpdateFromPrefs();
+
   // Called from UI to retrieve the stored proxy configuration, which is either
   // the last proxy config of the current network or the one last set by
   // SetProxyConfig.
@@ -65,7 +65,12 @@
   UIProxyConfig current_ui_config_;
 
   bool signin_screen_;
-  PrefService* pref_service_;
+
+  // Not owned.
+  PrefService* profile_prefs_;
+
+  // Not owned.
+  PrefService* local_state_prefs_;
 
   DISALLOW_COPY_AND_ASSIGN(UIProxyConfigService);
 };
diff --git a/chrome/browser/component_updater/component_updater_configurator.cc b/chrome/browser/component_updater/component_updater_configurator.cc
index d211e5e..f85c7db 100644
--- a/chrome/browser/component_updater/component_updater_configurator.cc
+++ b/chrome/browser/component_updater/component_updater_configurator.cc
@@ -10,7 +10,6 @@
 
 #include "base/command_line.h"
 #include "base/compiler_specific.h"
-#include "base/metrics/histogram.h"
 #include "base/strings/string_util.h"
 #include "base/win/windows_version.h"
 #include "build/build_config.h"
@@ -38,6 +37,10 @@
 const char kSwitchRequestParam[] = "test-request";
 // Disables differential updates.
 const char kSwitchDisableDeltaUpdates[] = "disable-delta-updates";
+// Disables pings. Pings are the requests sent to the update server that report
+// the success or the failure of component install or update attempts.
+extern const char kSwitchDisablePings[] = "disable-pings";
+
 // Sets the URL for updates.
 const char kSwitchUrlSource[] = "url-source";
 
@@ -46,6 +49,9 @@
 const char kDefaultUrlSource[] =
     "http://clients2.google.com/service/update2/crx";
 
+// The url to send the pings to.
+const char kPingUrl[] = "http://tools.google.com/service/update2";
+
 // 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())
@@ -89,11 +95,11 @@
   virtual int MinimumReCheckWait() OVERRIDE;
   virtual int OnDemandDelay() OVERRIDE;
   virtual GURL UpdateUrl() OVERRIDE;
+  virtual GURL PingUrl() 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;
 
@@ -103,6 +109,7 @@
   std::string url_source_;
   bool fast_update_;
   bool out_of_process_;
+  bool pings_enabled_;
   bool deltas_enabled_;
 };
 
@@ -113,6 +120,7 @@
             chrome::OmahaQueryParams::CHROME)),
         fast_update_(false),
         out_of_process_(false),
+        pings_enabled_(false),
         deltas_enabled_(false) {
   // Parse comma-delimited debug flags.
   std::vector<std::string> switch_values;
@@ -120,6 +128,7 @@
       ",", &switch_values);
   fast_update_ = HasSwitchValue(switch_values, kSwitchFastUpdate);
   out_of_process_ = HasSwitchValue(switch_values, kSwitchOutOfProcess);
+  pings_enabled_ = !HasSwitchValue(switch_values, kSwitchDisablePings);
 #if defined(OS_WIN)
   deltas_enabled_ = !HasSwitchValue(switch_values, kSwitchDisableDeltaUpdates);
 #else
@@ -166,6 +175,10 @@
   return GURL(url_source_);
 }
 
+GURL ChromeConfigurator::PingUrl() {
+  return pings_enabled_ ? GURL(kPingUrl) : GURL();
+}
+
 const char* ChromeConfigurator::ExtraRequestParams() {
   return extra_info_.c_str();
 }
@@ -182,32 +195,6 @@
   return !out_of_process_;
 }
 
-void ChromeConfigurator::OnEvent(Events event, int val) {
-  switch (event) {
-    case kManifestCheck:
-      UMA_HISTOGRAM_ENUMERATION("ComponentUpdater.ManifestCheck", val, 100);
-      break;
-    case kComponentUpdated:
-      UMA_HISTOGRAM_ENUMERATION("ComponentUpdater.ComponentUpdated", val, 100);
-      break;
-    case kManifestError:
-      UMA_HISTOGRAM_COUNTS_100("ComponentUpdater.ManifestError", val);
-      break;
-    case kNetworkError:
-      UMA_HISTOGRAM_ENUMERATION("ComponentUpdater.NetworkError", val, 100);
-      break;
-    case kUnpackError:
-      UMA_HISTOGRAM_ENUMERATION("ComponentUpdater.UnpackError", val, 100);
-      break;
-    case kInstallerError:
-      UMA_HISTOGRAM_ENUMERATION("ComponentUpdater.InstallError", val, 100);
-      break;
-    default:
-      NOTREACHED();
-      break;
-  }
-}
-
 ComponentPatcher* ChromeConfigurator::CreateComponentPatcher() {
 #if defined(OS_WIN)
   return new ComponentPatcherWin();
diff --git a/chrome/browser/component_updater/component_updater_ping_manager.cc b/chrome/browser/component_updater/component_updater_ping_manager.cc
new file mode 100644
index 0000000..e052bc3
--- /dev/null
+++ b/chrome/browser/component_updater/component_updater_ping_manager.cc
@@ -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.
+
+#include "chrome/browser/component_updater/component_updater_ping_manager.h"
+#include "base/guid.h"
+#include "base/logging.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/sys_info.h"
+#include "base/win/windows_version.h"
+#include "chrome/browser/component_updater/crx_update_item.h"
+#include "chrome/common/chrome_version_info.h"
+#include "chrome/common/omaha_query_params/omaha_query_params.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"
+
+namespace {
+
+// Returns true if the |update_item| contains a valid differential update url.
+bool HasDiffUpdate(const CrxUpdateItem* update_item) {
+  return update_item->diff_crx_url.is_valid();
+}
+
+}  // namespace
+
+namespace component_updater {
+
+// Sends a fire and forget ping. The instances of this class have no
+// ownership and they self-delete upon completion.
+class PingSender : public net::URLFetcherDelegate {
+ public:
+  PingSender();
+
+  void SendPing(const GURL& ping_url,
+                net::URLRequestContextGetter* url_request_context_getter,
+                const CrxUpdateItem* item);
+ private:
+  virtual ~PingSender();
+
+  // Overrides for URLFetcherDelegate.
+  virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE;
+
+  static std::string BuildPing(const CrxUpdateItem* item);
+  static std::string BuildPingEventElement(const CrxUpdateItem* item);
+
+  scoped_ptr<net::URLFetcher> url_fetcher_;
+
+  DISALLOW_COPY_AND_ASSIGN(PingSender);
+};
+
+PingSender::PingSender() {}
+
+PingSender::~PingSender() {}
+
+void PingSender::OnURLFetchComplete(const net::URLFetcher* source) {
+  delete this;
+}
+
+void PingSender::SendPing(
+    const GURL& ping_url,
+    net::URLRequestContextGetter* url_request_context_getter,
+    const CrxUpdateItem* item) {
+  DCHECK(item);
+
+  if (!ping_url.is_valid())
+    return;
+
+  url_fetcher_.reset(net::URLFetcher::Create(0,
+                                             ping_url,
+                                             net::URLFetcher::POST,
+                                             this));
+
+  url_fetcher_->SetUploadData("application/xml", BuildPing(item));
+  url_fetcher_->SetRequestContext(url_request_context_getter);
+  url_fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES |
+                             net::LOAD_DO_NOT_SAVE_COOKIES |
+                             net::LOAD_DISABLE_CACHE);
+  url_fetcher_->SetAutomaticallyRetryOn5xx(false);
+  url_fetcher_->Start();
+}
+
+// Builds a ping message for the specified update item.
+std::string PingSender::BuildPing(const CrxUpdateItem* item) {
+  const std::string prod_id(chrome::OmahaQueryParams::GetProdIdString(
+      chrome::OmahaQueryParams::CHROME));
+
+  const char response_format[] =
+      "<o:gupdate xmlns:o=\"http://www.google.com/update2/request\" "
+      "protocol=\"2.0\" version=\"%s-%s\" requestid=\"{%s}\"> "
+      "<o:os platform=\"%s\" version=\"%s\"/> "
+      "<o:app appid=\"%s\" version=\"%s\">"
+      "%s"
+      "</o:app></o:gupdate>";
+  const std::string response(
+      base::StringPrintf(response_format,
+                         prod_id.c_str(),
+                         chrome::VersionInfo().Version().c_str(),
+                         base::GenerateGUID().c_str(),
+                         chrome::VersionInfo().OSType().c_str(),
+                         base::SysInfo().OperatingSystemVersion().c_str(),
+                         item->id.c_str(),
+                         item->component.version.GetString().c_str(),
+                         BuildPingEventElement(item).c_str()));
+  return response;
+}
+
+// Returns a string representing one ping event xml element for an update item.
+std::string PingSender::BuildPingEventElement(const CrxUpdateItem* item) {
+  DCHECK(item->status == CrxUpdateItem::kNoUpdate ||
+         item->status == CrxUpdateItem::kUpdated);
+
+  using base::StringAppendF;
+
+  std::string ping_event("<o:event eventtype=\"3\"");
+  const int event_result = item->status == CrxUpdateItem::kUpdated;
+  StringAppendF(&ping_event, " eventresult=\"%d\"", event_result);
+  StringAppendF(&ping_event, " previousversion=\"%s\"",
+                item->previous_version.GetString().c_str());
+  StringAppendF(&ping_event, " nextversion=\"%s\"",
+                item->next_version.GetString().c_str());
+  if (item->error_category)
+    StringAppendF(&ping_event, " errorcat=\"%d\"", item->error_category);
+  if (item->error_code)
+    StringAppendF(&ping_event, " errorcode=\"%d\"", item->error_code);
+  if (item->extra_code1)
+    StringAppendF(&ping_event, " extracode1=\"%d\"", item->extra_code1);
+  if (HasDiffUpdate(item))
+    StringAppendF(&ping_event, " diffresult=\"%d\"", !item->diff_update_failed);
+  if (item->diff_error_category)
+    StringAppendF(&ping_event,
+                  " differrorcat=\"%d\"",
+                  item->diff_error_category);
+  if (item->diff_error_code)
+    StringAppendF(&ping_event, " differrorcode=\"%d\"", item->diff_error_code);
+  if (item->diff_extra_code1) {
+    StringAppendF(&ping_event,
+                  " diffextracode1=\"%d\"",
+                  item->diff_extra_code1);
+  }
+  if (!item->previous_fp.empty())
+    StringAppendF(&ping_event, " previousfp=\"%s\"", item->previous_fp.c_str());
+  if (!item->next_fp.empty())
+    StringAppendF(&ping_event, " nextfp=\"%s\"", item->next_fp.c_str());
+  StringAppendF(&ping_event, "/>");
+  return ping_event;
+}
+
+PingManager::PingManager(
+    const GURL& ping_url,
+    net::URLRequestContextGetter* url_request_context_getter)
+    : ping_url_(ping_url),
+      url_request_context_getter_(url_request_context_getter) {
+}
+
+PingManager::~PingManager() {
+}
+
+// Sends a fire and forget ping when the updates are complete. The ping
+// sender object self-deletes after sending the ping.
+void PingManager::OnUpdateComplete(const CrxUpdateItem* item) {
+  component_updater::PingSender* ping_sender(new PingSender);
+  ping_sender->SendPing(ping_url_, url_request_context_getter_, item);
+}
+
+}  // namespace component_updater
+
diff --git a/chrome/browser/component_updater/component_updater_ping_manager.h b/chrome/browser/component_updater/component_updater_ping_manager.h
new file mode 100644
index 0000000..1620245
--- /dev/null
+++ b/chrome/browser/component_updater/component_updater_ping_manager.h
@@ -0,0 +1,41 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_COMPONENT_UPDATER_COMPONENT_UPDATER_PING_MANAGER_H_
+#define CHROME_BROWSER_COMPONENT_UPDATER_COMPONENT_UPDATER_PING_MANAGER_H_
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "url/gurl.h"
+
+namespace net {
+class URLRequestContextGetter;
+}  // namespace net
+
+struct CrxUpdateItem;
+
+namespace component_updater {
+
+// Provides an event sink for completion events from ComponentUpdateService
+// and sends fire-and-forget pings when handling these events.
+class PingManager {
+ public:
+  PingManager(const GURL& ping_url,
+              net::URLRequestContextGetter* url_request_context_getter);
+  ~PingManager();
+
+  void OnUpdateComplete(const CrxUpdateItem* item);
+ private:
+  const GURL ping_url_;
+
+  // This member is not owned by this class.
+  net::URLRequestContextGetter* url_request_context_getter_;
+
+  DISALLOW_COPY_AND_ASSIGN(PingManager);
+};
+
+}  // namespace component_updater
+
+#endif  // CHROME_BROWSER_COMPONENT_UPDATER_COMPONENT_UPDATER_PING_MANAGER_H_
+
diff --git a/chrome/browser/component_updater/component_updater_service.cc b/chrome/browser/component_updater/component_updater_service.cc
index 8b4b88b..cd1ee8ef4 100644
--- a/chrome/browser/component_updater/component_updater_service.cc
+++ b/chrome/browser/component_updater/component_updater_service.cc
@@ -25,6 +25,8 @@
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/component_updater/component_patcher.h"
 #include "chrome/browser/component_updater/component_unpacker.h"
+#include "chrome/browser/component_updater/component_updater_ping_manager.h"
+#include "chrome/browser/component_updater/crx_update_item.h"
 #include "chrome/common/chrome_utility_messages.h"
 #include "chrome/common/chrome_version_info.h"
 #include "chrome/common/extensions/extension.h"
@@ -107,14 +109,6 @@
   return id;
 }
 
-// Returns given a crx id it returns a small number, less than 100, that has a
-// decent chance of being unique among the registered components. It also has
-// the nice property that can be trivially computed by hand.
-static int CrxIdtoUMAId(const std::string& id) {
-  CHECK_GT(id.size(), 2U);
-  return id[0] + id[1] + id[2] - ('a' * 3);
-}
-
 // Helper to do version check for components.
 bool IsVersionNewer(const Version& current, const std::string& proposed) {
   Version proposed_ver(proposed);
@@ -172,98 +166,29 @@
          (fetcher.GetResponseCode() == 200);
 }
 
-// This is the one and only per-item state structure. Designed to be hosted
-// in a std::vector or a std::list. The two main members are |component|
-// 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:
-//
-//                                 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,
-    kNoUpdate,
-    kLastStatus
-  };
+// Returns the error code which occured during the fetch.The function returns 0
+// if the fetch was successful. If errors happen, the function could return a
+// network error, an http response code, or the status of the fetch, if the
+// fetch is pending or canceled.
+int GetFetchError(const net::URLFetcher& fetcher) {
+  if (FetchSuccess(fetcher))
+    return 0;
 
-  Status status;
-  std::string id;
-  CrxComponent component;
+  const net::URLRequestStatus::Status status(fetcher.GetStatus().status());
+  if (status == net::URLRequestStatus::FAILED)
+    return fetcher.GetStatus().error();
 
-  base::Time last_check;
+  if (status == net::URLRequestStatus::IO_PENDING ||
+      status == net::URLRequestStatus::CANCELED)
+    return status;
 
-  // 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;
+  const int response_code(fetcher.GetResponseCode());
+  if (status == net::URLRequestStatus::SUCCESS && response_code != 200)
+    return response_code;
 
-  // 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) {
+  return -1;
   }
 
-  // Function object used to find a specific component.
-  class FindById {
-   public:
-    explicit FindById(const std::string& id) : id_(id) {}
-
-    bool operator() (CrxUpdateItem* item) const {
-      return (item->id == id_);
-    }
-   private:
-    const std::string& id_;
-  };
-};
-
 // 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();
@@ -278,7 +203,21 @@
          config.DeltasEnabled();
 }
 
-}  // namespace.
+}  // namespace
+
+CrxUpdateItem::CrxUpdateItem()
+    : status(kNew),
+      diff_update_failed(false),
+      error_category(0),
+      error_code(0),
+      extra_code1(0),
+      diff_error_category(0),
+      diff_error_code(0),
+      diff_extra_code1(0) {
+}
+
+CrxUpdateItem::~CrxUpdateItem() {
+}
 
 CrxComponent::CrxComponent()
     : installer(NULL) {
@@ -370,9 +309,15 @@
                           CRXContext* context);
 
  private:
+  enum ErrorCategory {
+    kErrorNone = 0,
+    kNetworkError,
+    kUnpackError,
+    kInstallError,
+  };
+
   // See ManifestParserBridge.
-  void OnParseUpdateManifestSucceeded(
-      const UpdateManifest::Results& results);
+  void OnParseUpdateManifestSucceeded(const UpdateManifest::Results& results);
 
   // See ManifestParserBridge.
   void OnParseUpdateManifestFailed(const std::string& error_message);
@@ -402,6 +347,8 @@
 
   scoped_ptr<net::URLFetcher> url_fetcher_;
 
+  scoped_ptr<component_updater::PingManager> ping_manager_;
+
   // A collection of every work item.
   typedef std::vector<CrxUpdateItem*> UpdateItems;
   UpdateItems work_items_;
@@ -424,11 +371,14 @@
 CrxUpdateService::CrxUpdateService(ComponentUpdateService::Configurator* config)
     : config_(config),
       component_patcher_(config->CreateComponentPatcher()),
+      ping_manager_(new component_updater::PingManager(
+          config->PingUrl(),
+          config->RequestContext())),
       chrome_version_(chrome::VersionInfo().Version()),
       prod_id_(chrome::OmahaQueryParams::GetProdIdString(
           chrome::OmahaQueryParams::CHROME)),
       running_(false) {
-}
+ }
 
 CrxUpdateService::~CrxUpdateService() {
   // Because we are a singleton, at this point only the UI thread should be
@@ -436,7 +386,7 @@
   // flight in other threads.
   Stop();
   STLDeleteElements(&work_items_);
-}
+ }
 
 ComponentUpdateService::Status CrxUpdateService::Start() {
   // Note that RegisterComponent will call Start() when the first
@@ -586,6 +536,12 @@
   item->previous_fp = item->component.fingerprint;
   item->next_fp.clear();
   item->diff_update_failed = false;
+  item->error_category = 0;
+  item->error_code = 0;
+  item->extra_code1 = 0;
+  item->diff_error_category = 0;
+  item->diff_error_code = 0;
+  item->diff_extra_code1 = 0;
   return true;
 }
 
@@ -801,8 +757,6 @@
     if (crx->status != CrxUpdateItem::kChecking)
       continue;  // Not updating this component now.
 
-    config_->OnEvent(Configurator::kManifestCheck, CrxIdtoUMAId(crx->id));
-
     if (it->version.empty()) {
       // No version means no update available.
       crx->status = CrxUpdateItem::kNoUpdate;
@@ -823,9 +777,7 @@
     // 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;
@@ -850,7 +802,6 @@
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   size_t count = ChangeItemStatus(CrxUpdateItem::kChecking,
                                   CrxUpdateItem::kNoUpdate);
-  config_->OnEvent(Configurator::kManifestError, static_cast<int>(count));
   DCHECK_GT(count, 0ul);
   ScheduleNextRun(false);
 }
@@ -869,19 +820,28 @@
 
   if (source->FileErrorOccurred(&error_code) || !FetchSuccess(*source)) {
     if (crx->status == CrxUpdateItem::kDownloadingDiff) {
+      crx->diff_error_category = kNetworkError;
+      crx->diff_error_code = GetFetchError(*source);
       crx->diff_update_failed = true;
       size_t count = ChangeItemStatus(CrxUpdateItem::kDownloadingDiff,
                                       CrxUpdateItem::kCanUpdate);
       DCHECK_EQ(count, 1ul);
+      url_fetcher_.reset();
+
       ScheduleNextRun(true);
       return;
     }
+    crx->error_category = kNetworkError;
+    crx->error_code = GetFetchError(*source);
     size_t count = ChangeItemStatus(CrxUpdateItem::kDownloading,
                                     CrxUpdateItem::kNoUpdate);
     DCHECK_EQ(count, 1ul);
-    config_->OnEvent(Configurator::kNetworkError, CrxIdtoUMAId(context->id));
     url_fetcher_.reset();
 
+    // At this point, since both the differential and the full downloads failed,
+    // the update for this component has finished with an error.
+    ping_manager_->OnUpdateComplete(crx);
+
     ScheduleNextRun(false);
   } else {
     base::FilePath temp_crx_path;
@@ -942,15 +902,32 @@
 }
 
 // Installation has been completed. Adjust the component status and
-// schedule the next check.
+// schedule the next check. Schedule a short delay before trying the full
+// update when the differential update failed.
 void CrxUpdateService::DoneInstalling(const std::string& component_id,
                                       ComponentUnpacker::Error error,
                                       int extra_code) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 
+  ErrorCategory error_category = kErrorNone;
+  switch (error) {
+    case ComponentUnpacker::kNone:
+      break;
+    case ComponentUnpacker::kInstallerError:
+      error_category = kInstallError;
+      break;
+    default:
+      error_category = kUnpackError;
+      break;
+  }
+
+  const bool is_success = error == ComponentUnpacker::kNone;
+
   CrxUpdateItem* item = FindUpdateItemById(component_id);
-  if (item->status == CrxUpdateItem::kUpdatingDiff) {
-    if (error != ComponentUnpacker::kNone) {
+  if (item->status == CrxUpdateItem::kUpdatingDiff && !is_success) {
+    item->diff_error_category = error_category;
+    item->diff_error_code = error;
+    item->diff_extra_code1 = extra_code;
       item->diff_update_failed = true;
       size_t count = ChangeItemStatus(CrxUpdateItem::kUpdatingDiff,
                                       CrxUpdateItem::kCanUpdate);
@@ -958,29 +935,20 @@
       ScheduleNextRun(true);
       return;
     }
-  }
 
-  item->status = (error == ComponentUnpacker::kNone) ? CrxUpdateItem::kUpdated :
-                                                       CrxUpdateItem::kNoUpdate;
-  if (item->status == CrxUpdateItem::kUpdated) {
+  if (is_success) {
+    item->status = CrxUpdateItem::kUpdated;
     item->component.version = item->next_version;
     item->component.fingerprint = item->next_fp;
+  } else {
+    item->status = CrxUpdateItem::kNoUpdate;
+    item->error_category = error_category;
+    item->error_code = error;
+    item->extra_code1 = extra_code;
   }
 
-  Configurator::Events event;
-  switch (error) {
-    case ComponentUnpacker::kNone:
-      event = Configurator::kComponentUpdated;
-      break;
-    case ComponentUnpacker::kInstallerError:
-      event = Configurator::kInstallerError;
-      break;
-    default:
-      event = Configurator::kUnpackError;
-      break;
-  }
+  ping_manager_->OnUpdateComplete(item);
 
-  config_->OnEvent(event, CrxIdtoUMAId(component_id));
   ScheduleNextRun(false);
 }
 
diff --git a/chrome/browser/component_updater/component_updater_service.h b/chrome/browser/component_updater/component_updater_service.h
index de1748b..7125ff4 100644
--- a/chrome/browser/component_updater/component_updater_service.h
+++ b/chrome/browser/component_updater/component_updater_service.h
@@ -11,15 +11,15 @@
 #include "base/version.h"
 #include "url/gurl.h"
 
-namespace net {
-class URLRequestContextGetter;
-}
-
 namespace base {
 class DictionaryValue;
 class FilePath;
 }
 
+namespace net {
+class URLRequestContextGetter;
+}
+
 class ComponentPatcher;
 
 // Component specific installers must derive from this class and implement
@@ -91,15 +91,6 @@
   // Controls the component updater behavior.
   class Configurator {
    public:
-    enum Events {
-      kManifestCheck,
-      kComponentUpdated,
-      kManifestError,
-      kNetworkError,
-      kUnpackError,
-      kInstallerError
-    };
-
     virtual ~Configurator() {}
     // Delay in seconds from calling Start() to the first update check.
     virtual int InitialDelay() = 0;
@@ -114,6 +105,9 @@
     virtual int OnDemandDelay() = 0;
     // The url that is going to be used update checks over Omaha protocol.
     virtual GURL UpdateUrl() = 0;
+    // The url where the completion pings are sent. Invalid if and only if
+    // pings are disabled.
+    virtual GURL PingUrl() = 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.
@@ -122,10 +116,6 @@
     virtual net::URLRequestContextGetter* RequestContext() = 0;
     // True means that all ops are performed in this process.
     virtual bool InProcess() = 0;
-    // The component updater will call this function when an interesting event
-    // 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;
diff --git a/chrome/browser/component_updater/crx_update_item.h b/chrome/browser/component_updater/crx_update_item.h
new file mode 100644
index 0000000..9378401
--- /dev/null
+++ b/chrome/browser/component_updater/crx_update_item.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_COMPONENT_UPDATER_CRX_UPDATE_ITEM_H_
+#define CHROME_BROWSER_COMPONENT_UPDATER_CRX_UPDATE_ITEM_H_
+
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/time/time.h"
+#include "base/version.h"
+#include "chrome/browser/component_updater/component_updater_service.h"
+
+// This is the one and only per-item state structure. Designed to be hosted
+// in a std::vector or a std::list. The two main members are |component|
+// 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:
+//
+//                                 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,
+    kNoUpdate,
+    kLastStatus
+  };
+
+  Status status;
+  std::string id;
+  CrxComponent component;
+
+  base::Time last_check;
+
+  // The url the full and differential update CRXs are downloaded from.
+  GURL crx_url;
+  GURL diff_crx_url;
+
+  // 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;
+
+  // The error information for full and differential updates.
+  // The |error_category| contains a hint about which module in the component
+  // updater generated the error. The |error_code| constains the error and
+  // the |extra_code1| usually contains a system error, but it can contain
+  // any extended information that is relevant to either the category or the
+  // error itself.
+  int error_category;
+  int error_code;
+  int extra_code1;
+  int diff_error_category;
+  int diff_error_code;
+  int diff_extra_code1;
+
+  CrxUpdateItem();
+  ~CrxUpdateItem();
+
+  // Function object used to find a specific component.
+  class FindById {
+   public:
+    explicit FindById(const std::string& id) : id_(id) {}
+
+    bool operator() (CrxUpdateItem* item) const {
+      return (item->id == id_);
+    }
+   private:
+    const std::string& id_;
+  };
+};
+
+#endif  // CHROME_BROWSER_COMPONENT_UPDATER_CRX_UPDATE_ITEM_H_
diff --git a/chrome/browser/component_updater/pepper_flash_component_installer.cc b/chrome/browser/component_updater/pepper_flash_component_installer.cc
index 0b1e359..0897fe6 100644
--- a/chrome/browser/component_updater/pepper_flash_component_installer.cc
+++ b/chrome/browser/component_updater/pepper_flash_component_installer.cc
@@ -155,22 +155,22 @@
 
   plugin_info->version = flash_version.GetString();
 
-  webkit::WebPluginMimeType swf_mime_type(kFlashPluginSwfMimeType,
-                                          kFlashPluginSwfExtension,
-                                          kFlashPluginName);
+  content::WebPluginMimeType swf_mime_type(kFlashPluginSwfMimeType,
+                                           kFlashPluginSwfExtension,
+                                           kFlashPluginName);
   plugin_info->mime_types.push_back(swf_mime_type);
-  webkit::WebPluginMimeType spl_mime_type(kFlashPluginSplMimeType,
-                                          kFlashPluginSplExtension,
-                                          kFlashPluginName);
+  content::WebPluginMimeType spl_mime_type(kFlashPluginSplMimeType,
+                                           kFlashPluginSplExtension,
+                                           kFlashPluginName);
   plugin_info->mime_types.push_back(spl_mime_type);
   return true;
 }
 
-bool IsPepperFlash(const webkit::WebPluginInfo& plugin) {
+bool IsPepperFlash(const content::WebPluginInfo& plugin) {
   // We try to recognize Pepper Flash by the following criteria:
   // * It is a Pepper plug-in.
   // * It has the special Flash permissions.
-  return webkit::IsPepperPlugin(plugin) &&
+  return plugin.is_pepper_plugin() &&
          (plugin.pepper_permissions & ppapi::PERMISSION_FLASH);
 }
 
@@ -181,9 +181,9 @@
   if (!MakePepperFlashPluginInfo(path, version, true, &plugin_info))
     return;
 
-  std::vector<webkit::WebPluginInfo> plugins;
+  std::vector<content::WebPluginInfo> plugins;
   PluginService::GetInstance()->GetInternalPlugins(&plugins);
-  for (std::vector<webkit::WebPluginInfo>::const_iterator it = plugins.begin();
+  for (std::vector<content::WebPluginInfo>::const_iterator it = plugins.begin();
        it != plugins.end(); ++it) {
     if (!IsPepperFlash(*it))
       continue;
diff --git a/chrome/browser/component_updater/test/component_patcher_unittest.cc b/chrome/browser/component_updater/test/component_patcher_unittest.cc
index f121fc0..67256f9 100644
--- a/chrome/browser/component_updater/test/component_patcher_unittest.cc
+++ b/chrome/browser/component_updater/test/component_patcher_unittest.cc
@@ -77,11 +77,11 @@
   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);
+                                            input_dir_.path(),
+                                            unpack_dir_.path(),
+                                            patcher_.get(),
+                                            NULL,
+                                            &error);
 
   EXPECT_EQ(ComponentUnpacker::kNone, result);
   EXPECT_EQ(0, error);
@@ -105,11 +105,74 @@
   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);
+                                            input_dir_.path(),
+                                            unpack_dir_.path(),
+                                            patcher_.get(),
+                                            installer_.get(),
+                                            &error);
+  EXPECT_EQ(ComponentUnpacker::kNone, result);
+  EXPECT_EQ(0, error);
+  EXPECT_TRUE(base::ContentsEqual(
+      unpack_dir_.path().Append(FILE_PATH_LITERAL("output.bin")),
+      test_file("binary_output.bin")));
+}
+
+// Verify that a 'courgette' delta update operation works correctly.
+TEST_F(ComponentPatcherOperationTest, CheckCourgetteOperation) {
+  EXPECT_TRUE(base::CopyFile(
+      test_file("binary_input.bin"),
+      installed_dir_.path().Append(FILE_PATH_LITERAL("binary_input.bin"))));
+  EXPECT_TRUE(base::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(base::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(base::CopyFile(
+      test_file("binary_input.bin"),
+      installed_dir_.path().Append(FILE_PATH_LITERAL("binary_input.bin"))));
+  EXPECT_TRUE(base::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(base::ContentsEqual(
diff --git a/chrome/browser/component_updater/test/component_patcher_unittest_win.cc b/chrome/browser/component_updater/test/component_patcher_unittest_win.cc
deleted file mode 100644
index afec59d..0000000
--- a/chrome/browser/component_updater/test/component_patcher_unittest_win.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 "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(base::CopyFile(
-      test_file("binary_input.bin"),
-      installed_dir_.path().Append(FILE_PATH_LITERAL("binary_input.bin"))));
-  EXPECT_TRUE(base::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(base::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(base::CopyFile(
-      test_file("binary_input.bin"),
-      installed_dir_.path().Append(FILE_PATH_LITERAL("binary_input.bin"))));
-  EXPECT_TRUE(base::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(base::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 edc1512..7a66d55 100644
--- a/chrome/browser/component_updater/test/component_updater_service_unittest.cc
+++ b/chrome/browser/component_updater/test/component_updater_service_unittest.cc
@@ -2,43 +2,35 @@
 // 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 "chrome/browser/component_updater/test/component_updater_service_unittest.h"
 #include "base/file_util.h"
 #include "base/files/file_path.h"
 #include "base/memory/scoped_vector.h"
-#include "base/message_loop/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/chrome_notification_types.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_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;
 
 TestConfigurator::TestConfigurator()
-    : times_(1), recheck_time_(0), ondemand_time_(0), cus_(NULL) {
+    : times_(1),
+      recheck_time_(0),
+      ondemand_time_(0),
+      cus_(NULL),
+      context_(new net::TestURLRequestContextGetter(
+          BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO))) {
 }
 
 TestConfigurator::~TestConfigurator() {
@@ -86,20 +78,21 @@
   return GURL("http://localhost/upd");
 }
 
+GURL TestConfigurator::PingUrl() {
+  return GURL("http://localhost2/ping");
+}
+
 const char* TestConfigurator::ExtraRequestParams() { return "extra=foo"; }
 
 size_t TestConfigurator::UrlSizeLimit() { return 256; }
 
 net::URLRequestContextGetter* TestConfigurator::RequestContext() {
-  return new net::TestURLRequestContextGetter(
-      BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO));
+  return context_.get();
 }
 
 // Don't use the utility process to decode files.
 bool TestConfigurator::InProcess() { return true; }
 
-void TestConfigurator::OnEvent(Events event, int extra) { }
-
 ComponentPatcher* TestConfigurator::CreateComponentPatcher() {
   return new MockComponentPatcher();
 }
@@ -128,11 +121,16 @@
   cus_ = cus;
 }
 
-ComponentUpdaterTest::ComponentUpdaterTest() : test_config_(NULL) {
+ComponentUpdaterTest::ComponentUpdaterTest()
+    : test_config_(NULL),
+      ui_thread_(BrowserThread::UI, &message_loop_),
+      file_thread_(BrowserThread::FILE),
+      io_thread_(BrowserThread::IO) {
   // 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");
@@ -150,6 +148,9 @@
         notifications[ix], content::NotificationService::AllSources());
   }
   net::URLFetcher::SetEnableInterceptionForTests(true);
+
+  io_thread_.StartIOThread();
+  file_thread_.Start();
 }
 
 ComponentUpdaterTest::~ComponentUpdaterTest() {
@@ -197,6 +198,48 @@
   return component_updater_->RegisterComponent(*com);
 }
 
+PingChecker::PingChecker(const std::map<std::string, std::string>& attributes)
+    : num_hits_(0), num_misses_(0), attributes_(attributes) {
+}
+
+PingChecker::~PingChecker() {}
+
+void PingChecker::Trial(net::URLRequest* request) {
+  if (Test(request))
+    ++num_hits_;
+  else
+    ++num_misses_;
+}
+
+bool PingChecker::Test(net::URLRequest* request) {
+  if (request->has_upload()) {
+    const net::UploadDataStream* stream = request->get_upload();
+    const net::UploadBytesElementReader* reader =
+        stream->element_readers()[0]->AsBytesReader();
+    int size = reader->length();
+    scoped_refptr <net::IOBuffer> buffer = new net::IOBuffer(size);
+    std::string data(reader->bytes());
+    // For now, we assume that there is only one ping per POST.
+    std::string::size_type start = data.find("<o:event");
+    if (start != std::string::npos) {
+      std::string::size_type end = data.find(">", start);
+      if (end != std::string::npos) {
+        std::string ping = data.substr(start, end - start);
+        std::map<std::string, std::string>::const_iterator iter;
+        for (iter = attributes_.begin(); iter != attributes_.end(); ++iter) {
+          // does the ping contain the specified attribute/value?
+          if (ping.find(std::string(" ") + (iter->first) +
+              std::string("=") + (iter->second)) == string::npos) {
+            return false;
+          }
+        }
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
 // Verify that our test fixture work and the component updater can
 // be created and destroyed with no side effects.
 TEST_F(ComponentUpdaterTest, VerifyFixture) {
@@ -208,11 +251,8 @@
 // start-shutdown situation. Failure of this test will be a crash. Also
 // if there is no work to do, there are no notifications generated.
 TEST_F(ComponentUpdaterTest, StartStop) {
-  base::MessageLoop message_loop;
-  content::TestBrowserThread ui_thread(BrowserThread::UI, &message_loop);
-
   component_updater()->Start();
-  message_loop.RunUntilIdle();
+  message_loop_.RunUntilIdle();
   component_updater()->Stop();
 
   EXPECT_EQ(0ul, notification_tracker().size());
@@ -222,14 +262,6 @@
 // the COMPONENT_UPDATER_STARTED and COMPONENT_UPDATER_SLEEPING notifications
 // are generated.
 TEST_F(ComponentUpdaterTest, CheckCrxSleep) {
-  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;
@@ -255,7 +287,7 @@
   TestNotificationTracker::Event ev1 = notification_tracker().at(0);
   EXPECT_EQ(chrome::NOTIFICATION_COMPONENT_UPDATER_STARTED, ev1.type);
 
-  message_loop.Run();
+  message_loop_.Run();
 
   ASSERT_EQ(3ul, notification_tracker().size());
   TestNotificationTracker::Event ev2 = notification_tracker().at(1);
@@ -279,7 +311,7 @@
   test_configurator()->SetLoopCount(2);
   component_updater()->Start();
 
-  message_loop.Run();
+  message_loop_.Run();
 
   ASSERT_EQ(3ul, notification_tracker().size());
   ev1 = notification_tracker().at(0);
@@ -300,19 +332,19 @@
 // the notifications above NOTIFICATION_COMPONENT_UPDATE_FOUND and
 // NOTIFICATION_COMPONENT_UPDATE_READY should have been fired. We do two loops
 // so the second time around there should be nothing left to do.
-// We also check that only 3 network requests are issued:
+// We also check that only 3 non-ping network requests are issued:
 // 1- manifest check
 // 2- download crx
 // 3- second manifest check.
 TEST_F(ComponentUpdaterTest, InstallCrx) {
-  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();
-
+  std::map<std::string, std::string> map;
+  map.insert(std::pair<std::string, std::string>("eventtype", "\"3\""));
+  map.insert(std::pair<std::string, std::string>("eventresult", "\"1\""));
+  map.insert(std::pair<std::string, std::string>("previousversion",
+                                                 "\"0.9\""));
+  map.insert(std::pair<std::string, std::string>("nextversion", "\"1.0\""));
+  PingChecker ping_checker(map);
+  URLRequestPostInterceptor post_interceptor(&ping_checker);
   content::URLLocalHostRequestPrepackagedInterceptor interceptor;
 
   TestInstaller installer1;
@@ -342,7 +374,7 @@
   test_configurator()->SetLoopCount(2);
 
   component_updater()->Start();
-  message_loop.Run();
+  message_loop_.Run();
 
   EXPECT_EQ(0, static_cast<TestInstaller*>(com1.installer)->error());
   EXPECT_EQ(1, static_cast<TestInstaller*>(com1.installer)->install_count());
@@ -350,6 +382,8 @@
   EXPECT_EQ(0, static_cast<TestInstaller*>(com2.installer)->install_count());
 
   EXPECT_EQ(3, interceptor.GetHitCount());
+  EXPECT_EQ(1, ping_checker.NumHits());
+  EXPECT_EQ(0, ping_checker.NumMisses());
 
   ASSERT_EQ(5ul, notification_tracker().size());
 
@@ -372,14 +406,9 @@
 // particular there should not be an install because the minimum product
 // version is much higher than of chrome.
 TEST_F(ComponentUpdaterTest, ProdVersionCheck) {
-  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();
-
+  std::map<std::string, std::string> map;
+  PingChecker ping_checker(map);
+  URLRequestPostInterceptor post_interceptor(&ping_checker);
   content::URLLocalHostRequestPrepackagedInterceptor interceptor;
 
   TestInstaller installer;
@@ -397,8 +426,10 @@
 
   test_configurator()->SetLoopCount(1);
   component_updater()->Start();
-  message_loop.Run();
+  message_loop_.Run();
 
+  EXPECT_EQ(0, ping_checker.NumHits());
+  EXPECT_EQ(0, ping_checker.NumMisses());
   EXPECT_EQ(1, interceptor.GetHitCount());
   EXPECT_EQ(0, static_cast<TestInstaller*>(com.installer)->error());
   EXPECT_EQ(0, static_cast<TestInstaller*>(com.installer)->install_count());
@@ -413,14 +444,14 @@
 //  - We ping.
 //  - This triggers a second loop, which has a reply that triggers an install.
 TEST_F(ComponentUpdaterTest, CheckForUpdateSoon) {
-  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();
-
+  std::map<std::string, std::string> map;
+  map.insert(std::pair<std::string, std::string>("eventtype", "\"3\""));
+  map.insert(std::pair<std::string, std::string>("eventresult", "\"1\""));
+  map.insert(std::pair<std::string, std::string>("previousversion",
+                                                 "\"0.9\""));
+  map.insert(std::pair<std::string, std::string>("nextversion", "\"1.0\""));
+  PingChecker ping_checker(map);
+  URLRequestPostInterceptor post_interceptor(&ping_checker);
   content::URLLocalHostRequestPrepackagedInterceptor interceptor;
 
   TestInstaller installer1;
@@ -451,7 +482,7 @@
   test_configurator()->SetLoopCount(2);
   test_configurator()->AddComponentToCheck(&com2, 1);
   component_updater()->Start();
-  message_loop.Run();
+  message_loop_.Run();
 
   EXPECT_EQ(0, static_cast<TestInstaller*>(com1.installer)->error());
   EXPECT_EQ(0, static_cast<TestInstaller*>(com1.installer)->install_count());
@@ -501,7 +532,7 @@
   EXPECT_EQ(ComponentUpdateService::kOk,
             component_updater()->CheckForUpdateSoon(com2));
 
-  message_loop.Run();
+  message_loop_.Run();
 
   ASSERT_EQ(2ul, notification_tracker().size());
   ev0 = notification_tracker().at(0);
@@ -519,8 +550,10 @@
   EXPECT_EQ(ComponentUpdateService::kOk,
             component_updater()->CheckForUpdateSoon(com2));
 
-  message_loop.Run();
+  message_loop_.Run();
 
+  EXPECT_EQ(1, ping_checker.NumHits());
+  EXPECT_EQ(0, ping_checker.NumMisses());
   ASSERT_EQ(2ul, notification_tracker().size());
   ev0 = notification_tracker().at(0);
   EXPECT_EQ(chrome::NOTIFICATION_COMPONENT_UPDATER_STARTED, ev0.type);
@@ -532,14 +565,14 @@
 // Verify that a previously registered component can get re-registered
 // with a different version.
 TEST_F(ComponentUpdaterTest, CheckReRegistration) {
-  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();
-
+  std::map<std::string, std::string> map;
+  map.insert(std::pair<std::string, std::string>("eventtype", "\"3\""));
+  map.insert(std::pair<std::string, std::string>("eventresult", "\"1\""));
+  map.insert(std::pair<std::string, std::string>("previousversion",
+                                                 "\"0.9\""));
+  map.insert(std::pair<std::string, std::string>("nextversion", "\"1.0\""));
+  PingChecker ping_checker(map);
+  URLRequestPostInterceptor post_interceptor(&ping_checker);
   content::URLLocalHostRequestPrepackagedInterceptor interceptor;
 
   TestInstaller installer1;
@@ -572,13 +605,15 @@
   test_configurator()->SetLoopCount(2);
 
   component_updater()->Start();
-  message_loop.Run();
+  message_loop_.Run();
 
   EXPECT_EQ(0, static_cast<TestInstaller*>(com1.installer)->error());
   EXPECT_EQ(1, static_cast<TestInstaller*>(com1.installer)->install_count());
   EXPECT_EQ(0, static_cast<TestInstaller*>(com2.installer)->error());
   EXPECT_EQ(0, static_cast<TestInstaller*>(com2.installer)->install_count());
 
+  EXPECT_EQ(1, ping_checker.NumHits());
+  EXPECT_EQ(0, ping_checker.NumMisses());
   EXPECT_EQ(3, interceptor.GetHitCount());
 
   ASSERT_EQ(5ul, notification_tracker().size());
@@ -622,7 +657,7 @@
   // Loop once just to notice the check happening with the re-register version.
   test_configurator()->SetLoopCount(1);
   component_updater()->Start();
-  message_loop.Run();
+  message_loop_.Run();
 
   ASSERT_EQ(2ul, notification_tracker().size());
 
@@ -643,24 +678,91 @@
   component_updater()->Stop();
 }
 
+// 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 non-ping 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)
+// There should be two pings, one for each update. The second will bear a
+// diffresult=1, while the first will not.
+TEST_F(ComponentUpdaterTest, DifferentialUpdate) {
+  std::map<std::string, std::string> map;
+  map.insert(std::pair<std::string, std::string>("eventtype", "\"3\""));
+  map.insert(std::pair<std::string, std::string>("eventresult", "\"1\""));
+  map.insert(std::pair<std::string, std::string>("diffresult", "\"1\""));
+  PingChecker ping_checker(map);
+  URLRequestPostInterceptor post_interceptor(&ping_checker);
+  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());
+
+  // One ping has the diffresult=1, the other does not.
+  EXPECT_EQ(1, ping_checker.NumHits());
+  EXPECT_EQ(1, ping_checker.NumMisses());
+
+  EXPECT_EQ(5, interceptor.GetHitCount());
+
+  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:
+// We also check that exactly 4 non-ping 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)
+// There should be one ping for the first attempted update.
 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();
-
+  std::map<std::string, std::string> map;
+  map.insert(std::pair<std::string, std::string>("eventtype", "\"3\""));
+  map.insert(std::pair<std::string, std::string>("eventresult", "\"1\""));
+  map.insert(std::pair<std::string, std::string>("diffresult", "\"0\""));
+  map.insert(std::pair<std::string, std::string>("differrorcode", "\"16\""));
+  PingChecker ping_checker(map);
+  URLRequestPostInterceptor post_interceptor(&ping_checker);
   content::URLLocalHostRequestPrepackagedInterceptor interceptor;
 
   TestInstaller installer;
@@ -695,29 +797,92 @@
   test_configurator()->SetLoopCount(2);
 
   component_updater()->Start();
-  message_loop.Run();
+  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(1, ping_checker.NumHits());
+  EXPECT_EQ(0, ping_checker.NumMisses());
   EXPECT_EQ(4, interceptor.GetHitCount());
 
   component_updater()->Stop();
 }
 
+// Verify that a failed installation causes an install failure ping.
+TEST_F(ComponentUpdaterTest, CheckFailedInstallPing) {
+  std::map<std::string, std::string> map;
+  map.insert(std::pair<std::string, std::string>("eventtype", "\"3\""));
+  map.insert(std::pair<std::string, std::string>("eventresult", "\"0\""));
+  map.insert(std::pair<std::string, std::string>("errorcode", "\"9\""));
+  map.insert(std::pair<std::string, std::string>("previousversion",
+                                                 "\"0.9\""));
+  map.insert(std::pair<std::string, std::string>("nextversion", "\"1.0\""));
+  PingChecker ping_checker(map);
+  URLRequestPostInterceptor post_interceptor(&ping_checker);
+  content::URLLocalHostRequestPrepackagedInterceptor interceptor;
+
+  // This test installer reports installation failure.
+  class : public TestInstaller {
+    virtual bool Install(const base::DictionaryValue& manifest,
+                         const base::FilePath& unpack_path) OVERRIDE {
+      ++install_count_;
+      base::DeleteFile(unpack_path, true);
+      return false;
+    }
+  } installer;
+
+  CrxComponent com;
+  RegisterComponent(&com, kTestComponent_jebg, Version("0.9"), &installer);
+
+  // Start with 0.9, and attempt update to 1.0
+  const GURL expected_update_url_1(
+      "http://localhost/upd?extra=foo"
+      "&x=id%3Djebgalgnebhfojomionfpkfelancnnkf%26v%3D0.9%26fp%3D%26uc");
+
+  interceptor.SetResponse(expected_update_url_1,
+                          test_file("updatecheck_reply_1.xml"));
+  interceptor.SetResponse(GURL(expected_crx_url),
+                          test_file("jebgalgnebhfojomionfpkfelancnnkf.crx"));
+
+  // Loop twice to issue two checks: (1) with original 0.9 version
+  // and (2), which should retry with 0.9.
+  test_configurator()->SetLoopCount(2);
+  component_updater()->Start();
+  message_loop_.Run();
+
+  // Loop once more, but expect no ping because a noupdate response is issued.
+  // This is necessary to clear out the fire-and-forget ping from the previous
+  // iteration.
+  interceptor.SetResponse(expected_update_url_1,
+                          test_file("updatecheck_reply_noupdate.xml"));
+  test_configurator()->SetLoopCount(1);
+  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(2, ping_checker.NumHits());
+  EXPECT_EQ(0, ping_checker.NumMisses());
+  EXPECT_EQ(5, 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();
-
+  std::map<std::string, std::string> map;
+  map.insert(std::pair<std::string, std::string>("eventtype", "\"3\""));
+  map.insert(std::pair<std::string, std::string>("eventresult", "\"1\""));
+  map.insert(std::pair<std::string, std::string>("diffresult", "\"0\""));
+  map.insert(std::pair<std::string, std::string>("differrorcode", "\"14\""));
+  map.insert(std::pair<std::string, std::string>("diffextracode1", "\"305\""));
+  PingChecker ping_checker(map);
+  URLRequestPostInterceptor post_interceptor(&ping_checker);
   content::URLLocalHostRequestPrepackagedInterceptor interceptor;
 
   VersionedTestInstaller installer;
@@ -757,11 +922,13 @@
   test_configurator()->SetLoopCount(3);
 
   component_updater()->Start();
-  message_loop.Run();
+  message_loop_.Run();
 
   EXPECT_EQ(0, static_cast<TestInstaller*>(com.installer)->error());
   EXPECT_EQ(2, static_cast<TestInstaller*>(com.installer)->install_count());
 
+  EXPECT_EQ(1, ping_checker.NumHits());
+  EXPECT_EQ(1, ping_checker.NumMisses());
   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
index ba98102..ca3a7b8 100644
--- a/chrome/browser/component_updater/test/component_updater_service_unittest.h
+++ b/chrome/browser/component_updater/test/component_updater_service_unittest.h
@@ -6,18 +6,23 @@
 #define CHROME_BROWSER_COMPONENT_UPDATER_TEST_COMPONENT_UPDATER_SERVICE_UNITTEST_H_
 
 #include <list>
+#include <map>
+#include <string>
 #include <utility>
-
+#include "base/basictypes.h"
 #include "base/compiler_specific.h"
+#include "base/files/file_path.h"
+#include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.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/url_request_post_interceptor.h"
+#include "content/public/test/test_browser_thread.h"
 #include "content/public/test/test_notification_tracker.h"
+#include "net/url_request/url_request_test_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-using content::TestNotificationTracker;
-
-class GURL;
 class TestInstaller;
 
 // component 1 has extension id "jebgalgnebhfojomionfpkfelancnnkf", and
@@ -59,6 +64,8 @@
 
   virtual GURL UpdateUrl() OVERRIDE;
 
+  virtual GURL PingUrl() OVERRIDE;
+
   virtual const char* ExtraRequestParams() OVERRIDE;
 
   virtual size_t UrlSizeLimit() OVERRIDE;
@@ -68,8 +75,6 @@
   // 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;
@@ -91,6 +96,7 @@
 
   std::list<CheckAtLoopCount> components_to_check_;
   ComponentUpdateService* cus_;
+  scoped_refptr<net::TestURLRequestContextGetter> context_;
 };
 
 class ComponentUpdaterTest : public testing::Test {
@@ -112,7 +118,7 @@
   // Makes the full path to a component updater test file.
   const base::FilePath test_file(const char* file);
 
-  TestNotificationTracker& notification_tracker();
+  content::TestNotificationTracker& notification_tracker();
 
   TestConfigurator* test_configurator();
 
@@ -120,15 +126,42 @@
                                                    TestComponents component,
                                                    const Version& version,
                                                    TestInstaller* installer);
+ protected:
+  base::MessageLoop message_loop_;
 
  private:
-  scoped_ptr<ComponentUpdateService> component_updater_;
-  base::FilePath test_data_dir_;
-  TestNotificationTracker notification_tracker_;
   TestConfigurator* test_config_;
+  base::FilePath test_data_dir_;
+  content::TestNotificationTracker notification_tracker_;
+  content::TestBrowserThread ui_thread_;
+  content::TestBrowserThread file_thread_;
+  content::TestBrowserThread io_thread_;
+  scoped_ptr<ComponentUpdateService> component_updater_;
 };
 
 const char expected_crx_url[] =
     "http://localhost/download/jebgalgnebhfojomionfpkfelancnnkf.crx";
 
+class PingChecker : public RequestCounter {
+ public:
+  explicit PingChecker(const std::map<std::string, std::string>& attributes);
+
+  virtual ~PingChecker();
+
+  virtual void Trial(net::URLRequest* request) OVERRIDE;
+
+  int NumHits() const {
+    return num_hits_;
+  }
+  int NumMisses() const {
+    return num_misses_;
+  }
+
+ private:
+  int num_hits_;
+  int num_misses_;
+  const std::map<std::string, std::string> attributes_;
+  virtual bool Test(net::URLRequest* request);
+};
+
 #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
deleted file mode 100644
index 8a51010..0000000
--- a/chrome/browser/component_updater/test/component_updater_service_unittest_win.cc
+++ /dev/null
@@ -1,101 +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 <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/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/chrome_notification_types.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_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/url_request_post_interceptor.cc b/chrome/browser/component_updater/test/url_request_post_interceptor.cc
new file mode 100644
index 0000000..885c9c6
--- /dev/null
+++ b/chrome/browser/component_updater/test/url_request_post_interceptor.cc
@@ -0,0 +1,68 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/component_updater/test/url_request_post_interceptor.h"
+
+#include "content/public/test/test_browser_thread.h"
+#include "net/url_request/url_request.h"
+#include "net/url_request/url_request_filter.h"
+#include "net/url_request/url_request_test_util.h"
+
+using content::BrowserThread;
+
+URLRequestPostInterceptor::URLRequestPostInterceptor(
+    RequestCounter* counter) : delegate_(new Delegate(counter)) {
+  BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
+                          base::Bind(&Delegate::Register,
+                                     base::Unretained(delegate_)));
+}
+
+URLRequestPostInterceptor::~URLRequestPostInterceptor() {
+  BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
+                          base::Bind(&Delegate::Unregister,
+                                     base::Unretained(delegate_)));
+}
+
+URLRequestPostInterceptor::Delegate::Delegate(
+    RequestCounter* counter) : counter_(counter) {
+}
+
+void URLRequestPostInterceptor::Delegate::Register() {
+  net::URLRequestFilter::GetInstance()->AddHostnameProtocolHandler(
+      "http", "localhost2",
+      scoped_ptr<net::URLRequestJobFactory::ProtocolHandler>(this));
+}
+
+void URLRequestPostInterceptor::Delegate::Unregister() {
+  net::URLRequestFilter::GetInstance()->
+      RemoveHostnameHandler("http", "localhost2");
+}
+
+net::URLRequestJob* URLRequestPostInterceptor::Delegate::MaybeCreateJob(
+    net::URLRequest* request,
+    net::NetworkDelegate* network_delegate) const {
+  CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+  if (request->has_upload()) {
+    counter_->Trial(request);
+    return new URLRequestPingMockJob(request, network_delegate);
+  }
+  return NULL;
+}
+
+URLRequestPingMockJob::URLRequestPingMockJob(
+    net::URLRequest* request,
+    net::NetworkDelegate* network_delegate)
+    : net::URLRequestSimpleJob(request, network_delegate) {
+}
+
+int URLRequestPingMockJob::GetData(
+    std::string* mime_type,
+    std::string* charset,
+    std::string* data,
+    const net::CompletionCallback& callback) const {
+  mime_type->assign("text/plain");
+  charset->assign("US-ASCII");
+  data->assign("");  // There is no reason to have a response body.
+  return net::OK;
+}
diff --git a/chrome/browser/component_updater/test/url_request_post_interceptor.h b/chrome/browser/component_updater/test/url_request_post_interceptor.h
new file mode 100644
index 0000000..3d0af2b
--- /dev/null
+++ b/chrome/browser/component_updater/test/url_request_post_interceptor.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_COMPONENT_UPDATER_TEST_URL_REQUEST_POST_INTERCEPTOR_H_
+#define CHROME_BROWSER_COMPONENT_UPDATER_TEST_URL_REQUEST_POST_INTERCEPTOR_H_
+
+#include "base/basictypes.h"
+#include "net/url_request/url_request_job_factory.h"
+#include "net/url_request/url_request_simple_job.h"
+
+namespace net {
+class NetworkDelegate;
+class URLRequest;
+}
+
+class RequestCounter {
+ public:
+  virtual void Trial(net::URLRequest* request) = 0;
+};
+
+class URLRequestPostInterceptor {
+ public:
+  explicit URLRequestPostInterceptor(RequestCounter* counter);
+  virtual ~URLRequestPostInterceptor();
+
+ private:
+  class Delegate;
+
+  // After creation, |delegate_| lives on the IO thread, and a task to delete it
+  // is posted from ~URLRequestPostInterceptor().
+  Delegate* delegate_;
+
+  DISALLOW_COPY_AND_ASSIGN(URLRequestPostInterceptor);
+};
+
+class URLRequestPostInterceptor::Delegate
+    : public net::URLRequestJobFactory::ProtocolHandler {
+ public:
+  explicit Delegate(RequestCounter* counter);
+  virtual ~Delegate() {}
+
+  void Register();
+
+  void Unregister();
+
+ private:
+  RequestCounter* counter_;
+
+  virtual net::URLRequestJob* MaybeCreateJob(
+      net::URLRequest* request,
+      net::NetworkDelegate* network_delegate) const OVERRIDE;
+};
+
+class URLRequestPingMockJob : public net::URLRequestSimpleJob {
+ public:
+  URLRequestPingMockJob(net::URLRequest* request,
+                        net::NetworkDelegate* network_delegate);
+
+ protected:
+  virtual int GetData(std::string* mime_type,
+                      std::string* charset,
+                      std::string* data,
+                      const net::CompletionCallback& callback) const OVERRIDE;
+
+ private:
+  virtual ~URLRequestPingMockJob() {}
+
+  DISALLOW_COPY_AND_ASSIGN(URLRequestPingMockJob);
+};
+
+#endif  // CHROME_BROWSER_COMPONENT_UPDATER_TEST_URL_REQUEST_POST_INTERCEPTOR_H_
diff --git a/chrome/browser/component_updater/widevine_cdm_component_installer.cc b/chrome/browser/component_updater/widevine_cdm_component_installer.cc
index 400b94f..cdb9f24 100644
--- a/chrome/browser/component_updater/widevine_cdm_component_installer.cc
+++ b/chrome/browser/component_updater/widevine_cdm_component_installer.cc
@@ -134,7 +134,7 @@
   plugin_info->name = kWidevineCdmDisplayName;
   plugin_info->description = kWidevineCdmDescription;
   plugin_info->version = version.GetString();
-  webkit::WebPluginMimeType widevine_cdm_mime_type(
+  content::WebPluginMimeType widevine_cdm_mime_type(
       kWidevineCdmPluginMimeType,
       kWidevineCdmPluginExtension,
       kWidevineCdmPluginMimeTypeDescription);
diff --git a/chrome/browser/content_settings/content_settings_browsertest.cc b/chrome/browser/content_settings/content_settings_browsertest.cc
index bee7ee8..f13eea9 100644
--- a/chrome/browser/content_settings/content_settings_browsertest.cc
+++ b/chrome/browser/content_settings/content_settings_browsertest.cc
@@ -37,6 +37,10 @@
 #include "base/mac/scoped_nsautorelease_pool.h"
 #endif
 
+#if defined(OS_WIN) && defined(USE_ASH)
+#include "base/win/windows_version.h"
+#endif
+
 using content::BrowserThread;
 using content::URLRequestMockHTTPJob;
 
@@ -562,6 +566,12 @@
 
 // Tests Pepper plugins that use JavaScript instead of Plug-ins settings.
 IN_PROC_BROWSER_TEST_F(PepperContentSettingsTest, PluginSpecialCases) {
+#if defined(OS_WIN) && defined(USE_ASH)
+  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
+  if (base::win::GetVersion() >= base::win::VERSION_WIN8)
+    return;
+#endif
+
   HostContentSettingsMap* content_settings =
       browser()->profile()->GetHostContentSettingsMap();
 
diff --git a/chrome/browser/geolocation/geolocation_settings_state.cc b/chrome/browser/content_settings/content_settings_usages_state.cc
similarity index 80%
rename from chrome/browser/geolocation/geolocation_settings_state.cc
rename to chrome/browser/content_settings/content_settings_usages_state.cc
index 21cbb77..4e82b6f 100644
--- a/chrome/browser/geolocation/geolocation_settings_state.cc
+++ b/chrome/browser/content_settings/content_settings_usages_state.cc
@@ -1,8 +1,8 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/geolocation/geolocation_settings_state.h"
+#include "chrome/browser/content_settings/content_settings_usages_state.h"
 
 #include <string>
 
@@ -16,20 +16,22 @@
 #include "content/public/browser/navigation_entry.h"
 #include "net/base/net_util.h"
 
-GeolocationSettingsState::GeolocationSettingsState(Profile* profile)
-  : profile_(profile) {
+ContentSettingsUsagesState::ContentSettingsUsagesState(Profile* profile,
+                                                       ContentSettingsType type)
+    : profile_(profile),
+      type_(type) {
 }
 
-GeolocationSettingsState::~GeolocationSettingsState() {
+ContentSettingsUsagesState::~ContentSettingsUsagesState() {
 }
 
-void GeolocationSettingsState::OnGeolocationPermissionSet(
+void ContentSettingsUsagesState::OnPermissionSet(
     const GURL& requesting_origin, bool allowed) {
   state_map_[requesting_origin] =
       allowed ? CONTENT_SETTING_ALLOW : CONTENT_SETTING_BLOCK;
 }
 
-void GeolocationSettingsState::DidNavigate(
+void ContentSettingsUsagesState::DidNavigate(
     const content::LoadCommittedDetails& details) {
   if (details.entry)
     embedder_url_ = details.entry->GetURL();
@@ -47,18 +49,18 @@
     state_map_.clear();
 }
 
-void GeolocationSettingsState::ClearStateMap() {
+void ContentSettingsUsagesState::ClearStateMap() {
   state_map_.clear();
 }
 
-void GeolocationSettingsState::GetDetailedInfo(
+void ContentSettingsUsagesState::GetDetailedInfo(
     FormattedHostsPerState* formatted_hosts_per_state,
     unsigned int* tab_state_flags) const {
   DCHECK(tab_state_flags);
   DCHECK(embedder_url_.is_valid());
   ContentSetting default_setting =
       profile_->GetHostContentSettingsMap()->GetDefaultContentSetting(
-          CONTENT_SETTINGS_TYPE_GEOLOCATION, NULL);
+          type_, NULL);
   std::set<std::string> formatted_hosts;
   std::set<std::string> repeated_formatted_hosts;
 
@@ -87,10 +89,7 @@
 
     const ContentSetting saved_setting =
         profile_->GetHostContentSettingsMap()->GetContentSetting(
-            i->first,
-            embedder_url_,
-            CONTENT_SETTINGS_TYPE_GEOLOCATION,
-            std::string());
+            i->first, embedder_url_, type_, std::string());
     if (saved_setting != default_setting)
       *tab_state_flags |= TABSTATE_HAS_EXCEPTION;
     if (saved_setting != i->second)
@@ -100,7 +99,7 @@
   }
 }
 
-std::string GeolocationSettingsState::GURLToFormattedHost(
+std::string ContentSettingsUsagesState::GURLToFormattedHost(
     const GURL& url) const {
   string16 display_host;
   net::AppendFormattedHost(url,
diff --git a/chrome/browser/geolocation/geolocation_settings_state.h b/chrome/browser/content_settings/content_settings_usages_state.h
similarity index 65%
rename from chrome/browser/geolocation/geolocation_settings_state.h
rename to chrome/browser/content_settings/content_settings_usages_state.h
index c5f9948..e137620 100644
--- a/chrome/browser/geolocation/geolocation_settings_state.h
+++ b/chrome/browser/content_settings/content_settings_usages_state.h
@@ -1,14 +1,15 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_GEOLOCATION_GEOLOCATION_SETTINGS_STATE_H_
-#define CHROME_BROWSER_GEOLOCATION_GEOLOCATION_SETTINGS_STATE_H_
+#ifndef CHROME_BROWSER_CONTENT_SETTINGS_CONTENT_SETTINGS_USAGES_STATE_H_
+#define CHROME_BROWSER_CONTENT_SETTINGS_CONTENT_SETTINGS_USAGES_STATE_H_
 
 #include <map>
 #include <set>
 
 #include "chrome/common/content_settings.h"
+#include "chrome/common/content_settings_types.h"
 #include "url/gurl.h"
 
 class Profile;
@@ -17,12 +18,13 @@
 struct LoadCommittedDetails;
 }
 
-// This class manages the geolocation state per tab, and provides information
-// and presentation data about the geolocation usage.
-class GeolocationSettingsState {
+// This class manages a content setting state per tab for a given
+// |ContentSettingsType|, and provides information and presentation data about
+// the content setting usage.
+class ContentSettingsUsagesState {
  public:
-  explicit GeolocationSettingsState(Profile* profile);
-  virtual ~GeolocationSettingsState();
+  ContentSettingsUsagesState(Profile* profile, ContentSettingsType type);
+  virtual ~ContentSettingsUsagesState();
 
   typedef std::map<GURL, ContentSetting> StateMap;
   const StateMap& state_map() const {
@@ -30,7 +32,7 @@
   }
 
   // Sets the state for |requesting_origin|.
-  void OnGeolocationPermissionSet(const GURL& requesting_origin, bool allowed);
+  void OnPermissionSet(const GURL& requesting_origin, bool allowed);
 
   // Delegated by WebContents to indicate a navigation has happened and we
   // may need to clear our settings.
@@ -62,10 +64,11 @@
   std::string GURLToFormattedHost(const GURL& url) const;
 
   Profile* profile_;
+  ContentSettingsType type_;
   StateMap state_map_;
   GURL embedder_url_;
 
-  DISALLOW_COPY_AND_ASSIGN(GeolocationSettingsState);
+  DISALLOW_COPY_AND_ASSIGN(ContentSettingsUsagesState);
 };
 
-#endif  // CHROME_BROWSER_GEOLOCATION_GEOLOCATION_SETTINGS_STATE_H_
+#endif  // CHROME_BROWSER_CONTENT_SETTINGS_CONTENT_SETTINGS_USAGES_STATE_H_
diff --git a/chrome/browser/content_settings/content_settings_usages_state_unittest.cc b/chrome/browser/content_settings/content_settings_usages_state_unittest.cc
new file mode 100644
index 0000000..ef89d25
--- /dev/null
+++ b/chrome/browser/content_settings/content_settings_usages_state_unittest.cc
@@ -0,0 +1,219 @@
+// Copyright 2013 The Chromium Authors. 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/content_settings/content_settings_usages_state.h"
+
+#include <string>
+
+#include "base/message_loop/message_loop.h"
+#include "chrome/browser/content_settings/host_content_settings_map.h"
+#include "chrome/test/base/testing_profile.h"
+#include "content/public/browser/navigation_details.h"
+#include "content/public/browser/navigation_entry.h"
+#include "content/public/test/test_browser_thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using content::BrowserThread;
+using content::NavigationEntry;
+
+namespace {
+
+// ContentSettingsUsagesState class should work for any ContentSettingsType.
+// Here, following tests use |kTypeForTesting| as representation.
+// TODO(toyoshim): Add at least one test to verify the class works with other
+// types. http://crbug.com/263292 .
+ContentSettingsType kTypeForTesting = CONTENT_SETTINGS_TYPE_GEOLOCATION;
+
+class ContentSettingsUsagesStateTests : public testing::Test {
+ public:
+  ContentSettingsUsagesStateTests()
+    : ui_thread_(BrowserThread::UI, &message_loop_) {
+  }
+
+ protected:
+  base::MessageLoop message_loop_;
+  content::TestBrowserThread ui_thread_;
+};
+
+TEST_F(ContentSettingsUsagesStateTests, ClearOnNewOrigin) {
+  TestingProfile profile;
+  ContentSettingsUsagesState state(&profile, kTypeForTesting);
+  GURL url_0("http://www.example.com");
+
+  scoped_ptr<NavigationEntry> entry(NavigationEntry::Create());
+  entry->SetURL(url_0);
+  content::LoadCommittedDetails load_committed_details;
+  load_committed_details.entry = entry.get();
+  state.DidNavigate(load_committed_details);
+
+  profile.GetHostContentSettingsMap()->SetContentSetting(
+      ContentSettingsPattern::FromURLNoWildcard(url_0),
+      ContentSettingsPattern::FromURLNoWildcard(url_0),
+      kTypeForTesting,
+      std::string(),
+      CONTENT_SETTING_ALLOW);
+  state.OnPermissionSet(url_0, true);
+
+  GURL url_1("http://www.example1.com");
+  profile.GetHostContentSettingsMap()->SetContentSetting(
+      ContentSettingsPattern::FromURLNoWildcard(url_1),
+      ContentSettingsPattern::FromURLNoWildcard(url_0),
+      kTypeForTesting,
+      std::string(),
+      CONTENT_SETTING_BLOCK);
+  state.OnPermissionSet(url_1, false);
+
+  ContentSettingsUsagesState::StateMap state_map =
+      state.state_map();
+  EXPECT_EQ(2U, state_map.size());
+
+  ContentSettingsUsagesState::FormattedHostsPerState formatted_host_per_state;
+  unsigned int tab_state_flags = 0;
+  state.GetDetailedInfo(&formatted_host_per_state, &tab_state_flags);
+  EXPECT_TRUE(tab_state_flags &
+              ContentSettingsUsagesState::TABSTATE_HAS_ANY_ALLOWED)
+              << tab_state_flags;
+  EXPECT_TRUE(tab_state_flags &
+              ContentSettingsUsagesState::TABSTATE_HAS_EXCEPTION)
+              << tab_state_flags;
+  EXPECT_FALSE(tab_state_flags &
+               ContentSettingsUsagesState::TABSTATE_HAS_CHANGED)
+               << tab_state_flags;
+  EXPECT_TRUE(tab_state_flags &
+              ContentSettingsUsagesState::TABSTATE_HAS_ANY_ICON)
+              << tab_state_flags;
+  EXPECT_EQ(1U, formatted_host_per_state[CONTENT_SETTING_ALLOW].size());
+  EXPECT_EQ(1U,
+            formatted_host_per_state[CONTENT_SETTING_ALLOW].count(
+                url_0.host()));
+
+  EXPECT_EQ(1U, formatted_host_per_state[CONTENT_SETTING_BLOCK].size());
+  EXPECT_EQ(1U,
+            formatted_host_per_state[CONTENT_SETTING_BLOCK].count(
+                url_1.host()));
+
+  state.OnPermissionSet(url_0, false);
+
+  formatted_host_per_state.clear();
+  tab_state_flags = 0;
+  state.GetDetailedInfo(&formatted_host_per_state, &tab_state_flags);
+  EXPECT_FALSE(tab_state_flags &
+               ContentSettingsUsagesState::TABSTATE_HAS_ANY_ALLOWED)
+               << tab_state_flags;
+  EXPECT_TRUE(tab_state_flags &
+              ContentSettingsUsagesState::TABSTATE_HAS_EXCEPTION)
+              << tab_state_flags;
+  EXPECT_TRUE(tab_state_flags &
+              ContentSettingsUsagesState::TABSTATE_HAS_CHANGED)
+              << tab_state_flags;
+  EXPECT_TRUE(tab_state_flags &
+              ContentSettingsUsagesState::TABSTATE_HAS_ANY_ICON)
+              << tab_state_flags;
+  EXPECT_EQ(0U, formatted_host_per_state[CONTENT_SETTING_ALLOW].size());
+  EXPECT_EQ(2U, formatted_host_per_state[CONTENT_SETTING_BLOCK].size());
+  EXPECT_EQ(1U,
+            formatted_host_per_state[CONTENT_SETTING_BLOCK].count(
+                url_0.host()));
+  EXPECT_EQ(1U,
+            formatted_host_per_state[CONTENT_SETTING_BLOCK].count(
+                url_1.host()));
+
+  state.OnPermissionSet(url_0, true);
+
+  load_committed_details.previous_url = url_0;
+  state.DidNavigate(load_committed_details);
+
+  ContentSettingsUsagesState::StateMap new_state_map =
+      state.state_map();
+  EXPECT_EQ(state_map.size(), new_state_map.size());
+
+  GURL different_url("http://foo.com");
+  entry->SetURL(different_url);
+  state.DidNavigate(load_committed_details);
+
+  EXPECT_TRUE(state.state_map().empty());
+
+  formatted_host_per_state.clear();
+  tab_state_flags = 0;
+  state.GetDetailedInfo(&formatted_host_per_state, &tab_state_flags);
+  EXPECT_TRUE(formatted_host_per_state.empty());
+  EXPECT_EQ(0U, tab_state_flags);
+}
+
+TEST_F(ContentSettingsUsagesStateTests, ShowPortOnSameHost) {
+  TestingProfile profile;
+  ContentSettingsUsagesState state(&profile, kTypeForTesting);
+  GURL url_0("http://www.example.com");
+
+  scoped_ptr<NavigationEntry> entry(NavigationEntry::Create());
+  entry->SetURL(url_0);
+  content::LoadCommittedDetails load_committed_details;
+  load_committed_details.entry = entry.get();
+  state.DidNavigate(load_committed_details);
+
+  profile.GetHostContentSettingsMap()->SetContentSetting(
+      ContentSettingsPattern::FromURLNoWildcard(url_0),
+      ContentSettingsPattern::FromURLNoWildcard(url_0),
+      kTypeForTesting,
+      std::string(),
+      CONTENT_SETTING_ALLOW);
+  state.OnPermissionSet(url_0, true);
+
+  GURL url_1("https://www.example.com");
+  profile.GetHostContentSettingsMap()->SetContentSetting(
+      ContentSettingsPattern::FromURLNoWildcard(url_1),
+      ContentSettingsPattern::FromURLNoWildcard(url_0),
+      kTypeForTesting,
+      std::string(),
+      CONTENT_SETTING_ALLOW);
+  state.OnPermissionSet(url_1, true);
+
+  GURL url_2("http://www.example1.com");
+  profile.GetHostContentSettingsMap()->SetContentSetting(
+      ContentSettingsPattern::FromURLNoWildcard(url_2),
+      ContentSettingsPattern::FromURLNoWildcard(url_0),
+      kTypeForTesting,
+      std::string(),
+      CONTENT_SETTING_ALLOW);
+  state.OnPermissionSet(url_2, true);
+
+  ContentSettingsUsagesState::StateMap state_map =
+      state.state_map();
+  EXPECT_EQ(3U, state_map.size());
+
+  ContentSettingsUsagesState::FormattedHostsPerState formatted_host_per_state;
+  unsigned int tab_state_flags = 0;
+  state.GetDetailedInfo(&formatted_host_per_state, &tab_state_flags);
+
+  EXPECT_EQ(3U, formatted_host_per_state[CONTENT_SETTING_ALLOW].size());
+  EXPECT_EQ(1U,
+            formatted_host_per_state[CONTENT_SETTING_ALLOW].count(
+                url_0.spec()));
+  EXPECT_EQ(1U,
+            formatted_host_per_state[CONTENT_SETTING_ALLOW].count(
+                url_1.spec()));
+  EXPECT_EQ(1U,
+            formatted_host_per_state[CONTENT_SETTING_ALLOW].count(
+                url_2.host()));
+
+  state.OnPermissionSet(url_1, false);
+  formatted_host_per_state.clear();
+  tab_state_flags = 0;
+  state.GetDetailedInfo(&formatted_host_per_state, &tab_state_flags);
+
+  EXPECT_EQ(2U, formatted_host_per_state[CONTENT_SETTING_ALLOW].size());
+  EXPECT_EQ(1U,
+            formatted_host_per_state[CONTENT_SETTING_ALLOW].count(
+                url_0.spec()));
+  EXPECT_EQ(1U,
+            formatted_host_per_state[CONTENT_SETTING_ALLOW].count(
+                url_2.host()));
+  EXPECT_EQ(1U, formatted_host_per_state[CONTENT_SETTING_BLOCK].size());
+  EXPECT_EQ(1U,
+            formatted_host_per_state[CONTENT_SETTING_BLOCK].count(
+                url_1.spec()));
+}
+
+
+}  // namespace
diff --git a/chrome/browser/content_settings/tab_specific_content_settings.cc b/chrome/browser/content_settings/tab_specific_content_settings.cc
index 1ddd3e9..7b6d95b 100644
--- a/chrome/browser/content_settings/tab_specific_content_settings.cc
+++ b/chrome/browser/content_settings/tab_specific_content_settings.cc
@@ -79,7 +79,7 @@
       profile_(Profile::FromBrowserContext(tab->GetBrowserContext())),
       allowed_local_shared_objects_(profile_),
       blocked_local_shared_objects_(profile_),
-      geolocation_settings_state_(profile_),
+      geolocation_usages_state_(profile_, CONTENT_SETTINGS_TYPE_GEOLOCATION),
       pending_protocol_handler_(ProtocolHandler::EmptyProtocolHandler()),
       previous_protocol_handler_(ProtocolHandler::EmptyProtocolHandler()),
       pending_protocol_handler_setting_(CONTENT_SETTING_DEFAULT),
@@ -450,8 +450,7 @@
 void TabSpecificContentSettings::OnGeolocationPermissionSet(
     const GURL& requesting_origin,
     bool allowed) {
-  geolocation_settings_state_.OnGeolocationPermissionSet(requesting_origin,
-                                                         allowed);
+  geolocation_usages_state_.OnPermissionSet(requesting_origin, allowed);
   content::NotificationService::current()->Notify(
       chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED,
       content::Source<WebContents>(web_contents()),
@@ -547,11 +546,11 @@
 
 void TabSpecificContentSettings::GeolocationDidNavigate(
       const content::LoadCommittedDetails& details) {
-  geolocation_settings_state_.DidNavigate(details);
+  geolocation_usages_state_.DidNavigate(details);
 }
 
 void TabSpecificContentSettings::ClearGeolocationContentSettings() {
-  geolocation_settings_state_.ClearStateMap();
+  geolocation_usages_state_.ClearStateMap();
 }
 
 void TabSpecificContentSettings::SetPepperBrokerAllowed(bool allowed) {
diff --git a/chrome/browser/content_settings/tab_specific_content_settings.h b/chrome/browser/content_settings/tab_specific_content_settings.h
index ad1fa63..1cd3147 100644
--- a/chrome/browser/content_settings/tab_specific_content_settings.h
+++ b/chrome/browser/content_settings/tab_specific_content_settings.h
@@ -12,8 +12,8 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/observer_list.h"
+#include "chrome/browser/content_settings/content_settings_usages_state.h"
 #include "chrome/browser/content_settings/local_shared_objects_container.h"
-#include "chrome/browser/geolocation/geolocation_settings_state.h"
 #include "chrome/common/content_settings.h"
 #include "chrome/common/content_settings_types.h"
 #include "chrome/common/custom_handlers/protocol_handler.h"
@@ -188,10 +188,10 @@
   const std::set<std::string>& BlockedResourcesForType(
       ContentSettingsType content_type) const;
 
-  // Returns the GeolocationSettingsState that controls the
+  // Returns the ContentSettingsUsagesState that controls the
   // geolocation API usage on this page.
-  const GeolocationSettingsState& geolocation_settings_state() const {
-    return geolocation_settings_state_;
+  const ContentSettingsUsagesState& geolocation_usages_state() const {
+    return geolocation_usages_state_;
   }
 
   // Call to indicate that there is a protocol handler pending user approval.
@@ -353,7 +353,7 @@
   LocalSharedObjectsContainer blocked_local_shared_objects_;
 
   // Manages information about Geolocation API usage in this page.
-  GeolocationSettingsState geolocation_settings_state_;
+  ContentSettingsUsagesState geolocation_usages_state_;
 
   // The pending protocol handler, if any. This can be set if
   // registerProtocolHandler was invoked without user gesture.
diff --git a/chrome/browser/crash_upload_list.cc b/chrome/browser/crash_upload_list.cc
index 911fec4..12a069c 100644
--- a/chrome/browser/crash_upload_list.cc
+++ b/chrome/browser/crash_upload_list.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/crash_upload_list.h"
 
 #include "base/files/file_path.h"
+#include "base/message_loop/message_loop_proxy.h"
 #include "base/path_service.h"
 #include "chrome/common/chrome_paths.h"
 #if defined(OS_WIN)
@@ -29,6 +30,8 @@
 
 CrashUploadList::CrashUploadList(Delegate* delegate,
                                  const base::FilePath& upload_log_path)
-    : UploadList(delegate, upload_log_path) {}
+    : base::UploadList(delegate,
+                       upload_log_path,
+                       base::MessageLoopProxy::current()) {}
 
 CrashUploadList::~CrashUploadList() {}
diff --git a/chrome/browser/crash_upload_list.h b/chrome/browser/crash_upload_list.h
index f0b201c..b7ff6cf 100644
--- a/chrome/browser/crash_upload_list.h
+++ b/chrome/browser/crash_upload_list.h
@@ -5,10 +5,10 @@
 #ifndef CHROME_BROWSER_CRASH_UPLOAD_LIST_H_
 #define CHROME_BROWSER_CRASH_UPLOAD_LIST_H_
 
-#include "chrome/browser/upload_list.h"
+#include "base/upload_list.h"
 
 // An upload list manager for crash reports from breakpad.
-class CrashUploadList : public UploadList {
+class CrashUploadList : public base::UploadList {
  public:
   // Static factory method that creates the platform-specific implementation
   // of the crash upload list with the given callback delegate.
diff --git a/chrome/browser/custom_handlers/register_protocol_handler_infobar_delegate.h b/chrome/browser/custom_handlers/register_protocol_handler_infobar_delegate.h
index 3e73c14..90b7eae 100644
--- a/chrome/browser/custom_handlers/register_protocol_handler_infobar_delegate.h
+++ b/chrome/browser/custom_handlers/register_protocol_handler_infobar_delegate.h
@@ -16,9 +16,10 @@
 // card information gathered from a form submission.
 class RegisterProtocolHandlerInfoBarDelegate : public ConfirmInfoBarDelegate {
  public:
-  // Creates a new RPH delegate.  Searches |infobar_service| for an existing
-  // delegate for the same |handler|; replaces it with the new delegate if
-  // found, otherwise adds the new infobar to |infobar_service|.
+  // Creates a new register protocol handler infobar delegate.  Searches
+  // |infobar_service| for an existing delegate for the same |handler|; replaces
+  // it with the new delegate if found, otherwise adds the new infobar to
+  // |infobar_service|.
   static void Create(InfoBarService* infobar_service,
                      ProtocolHandlerRegistry* registry,
                      const ProtocolHandler& handler);
diff --git a/chrome/browser/devtools/adb/android_usb_device.cc b/chrome/browser/devtools/adb/android_usb_device.cc
index 82a8b8c..0f662d5 100644
--- a/chrome/browser/devtools/adb/android_usb_device.cc
+++ b/chrome/browser/devtools/adb/android_usb_device.cc
@@ -153,6 +153,20 @@
                                            zero_mask, devices));
 }
 
+static void InterfacesListed(
+    crypto::RSAPrivateKey* rsa_key,
+    scoped_refptr<UsbDevice> usb_device,
+    scoped_refptr<UsbConfigDescriptor> config,
+    AndroidUsbDevices* devices,
+    bool success) {
+  if (!success)
+    return;
+  for (size_t j = 0; j < config->GetNumInterfaces(); ++j) {
+    ClaimInterface(rsa_key, usb_device, config->GetInterface(j),
+                   devices);
+  }
+}
+
 static uint32 Checksum(const std::string& data) {
   unsigned char* x = (unsigned char*)data.data();
   int count = data.length();
@@ -209,7 +223,7 @@
 // static
 void AndroidUsbDevice::Enumerate(Profile* profile,
                                  crypto::RSAPrivateKey* rsa_key,
-                                 AndroidUsbDevices* devices) {
+                                 const AndroidUsbDevicesCallback& callback) {
   UsbService* service =
       UsbServiceFactory::GetInstance()->GetForProfile(profile);
   UsbDevices usb_devices;
@@ -237,21 +251,18 @@
   }
 
   // Add new devices.
-  AndroidUsbDevices new_devices;
   for (UsbDevices::iterator it = usb_devices.begin(); it != usb_devices.end();
        ++it) {
-    UsbDevice* usb_device = *it;
-    if (claimed_devices.find(usb_device) != claimed_devices.end())
+    scoped_refptr<UsbDevice> usb_device = *it;
+    if (claimed_devices.find(usb_device.get()) != claimed_devices.end())
       continue;
     scoped_refptr<UsbConfigDescriptor> config = new UsbConfigDescriptor();
-    usb_device->ListInterfaces(config.get(), base::Bind(&BoolNoop));
-    for (size_t j = 0; j < config->GetNumInterfaces(); ++j) {
-      ClaimInterface(rsa_key, usb_device, config->GetInterface(j),
-                     &g_devices.Get());
-    }
+    usb_device->ListInterfaces(config.get(),
+                               base::Bind(&InterfacesListed, rsa_key,
+                                          usb_device, config,
+                                          &g_devices.Get()));
   }
-
-  *devices = g_devices.Get();
+  callback.Run(g_devices.Get());
 }
 
 AndroidUsbDevice::AndroidUsbDevice(crypto::RSAPrivateKey* rsa_key,
@@ -331,12 +342,16 @@
     if (append_zero)
       body_buffer->data()[body_length - 1] = 0;
     outgoing_queue_.push(std::make_pair(body_buffer, body_length));
+    if (zero_mask_ && (body_length & zero_mask_) == 0) {
+      // Send a zero length packet.
+      outgoing_queue_.push(std::make_pair(body_buffer, 0));
+    }
   }
   ProcessOutgoing();
 }
 
 void AndroidUsbDevice::ProcessOutgoing() {
-  if (outgoing_queue_.empty())
+  if (outgoing_queue_.empty() || terminated_)
     return;
 
   BulkMessage message = outgoing_queue_.front();
@@ -358,6 +373,8 @@
 }
 
 void AndroidUsbDevice::ReadHeader(bool initial) {
+  if (terminated_)
+    return;
   if (!initial && HasOneRef())
     return;  // Stop polling.
   scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(kHeaderSize);
diff --git a/chrome/browser/devtools/adb/android_usb_device.h b/chrome/browser/devtools/adb/android_usb_device.h
index 67f50ff..6a8292d 100644
--- a/chrome/browser/devtools/adb/android_usb_device.h
+++ b/chrome/browser/devtools/adb/android_usb_device.h
@@ -62,12 +62,14 @@
 
 class AndroidUsbDevice;
 typedef std::vector<scoped_refptr<AndroidUsbDevice> > AndroidUsbDevices;
+typedef base::Callback<void(const AndroidUsbDevices&)>
+    AndroidUsbDevicesCallback;
 
 class AndroidUsbDevice : public base::RefCountedThreadSafe<AndroidUsbDevice> {
  public:
   static void Enumerate(Profile* profile,
                         crypto::RSAPrivateKey* rsa_key,
-                        AndroidUsbDevices* devices);
+                        const AndroidUsbDevicesCallback& callback);
 
   AndroidUsbDevice(crypto::RSAPrivateKey* rsa_key,
                    scoped_refptr<UsbDevice> device,
diff --git a/chrome/browser/devtools/adb/android_usb_socket.cc b/chrome/browser/devtools/adb/android_usb_socket.cc
index 63d1787..c9b87b4 100644
--- a/chrome/browser/devtools/adb/android_usb_socket.cc
+++ b/chrome/browser/devtools/adb/android_usb_socket.cc
@@ -159,7 +159,7 @@
 
 void AndroidUsbSocket::Disconnect() {
   is_connected_ = false;
-  device_->Send(AdbMessage::kCommandCLSE, local_id_, 0, "");
+  device_->Send(AdbMessage::kCommandCLSE, local_id_, remote_id_, "");
   RespondToReaders(true);
 }
 
diff --git a/chrome/browser/devtools/devtools_adb_bridge.cc b/chrome/browser/devtools/devtools_adb_bridge.cc
index 1a21127..a4cf6b7 100644
--- a/chrome/browser/devtools/devtools_adb_bridge.cc
+++ b/chrome/browser/devtools/devtools_adb_bridge.cc
@@ -23,7 +23,6 @@
 #include "base/threading/thread.h"
 #include "base/values.h"
 #include "chrome/browser/devtools/adb/android_rsa.h"
-#include "chrome/browser/devtools/adb/android_usb_device.h"
 #include "chrome/browser/devtools/adb_client_socket.h"
 #include "chrome/browser/devtools/devtools_window.h"
 #include "chrome/browser/devtools/tethering_adb_filter.h"
@@ -629,8 +628,9 @@
   void DisconnectOnHandlerThread(bool closed_by_device) {
     if (!socket_)
       return;
-    socket_->Disconnect();
-    socket_.reset();
+    // Wipe out socket_ first since Disconnect can re-enter this method.
+    scoped_ptr<net::StreamSocket> socket(socket_.release());
+    socket->Disconnect();
     BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
         base::Bind(&AdbWebSocket::OnSocketClosed, this, closed_by_device));
   }
@@ -864,22 +864,16 @@
 
 void DevToolsAdbBridge::EnumerateDevices(
     const AndroidDevicesCallback& callback) {
-  AdbClientSocket::AdbQuery(
-      kAdbPort, kHostDevicesCommand,
-      base::Bind(&DevToolsAdbBridge::ReceivedDevices, this, callback));
-}
+  DCHECK_EQ(base::MessageLoop::current(), adb_thread_->message_loop());
 
-void DevToolsAdbBridge::Query(
-    const std::string query,
-    const Callback& callback) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  if (!has_message_loop_) {
-    callback.Run(net::ERR_FAILED, "Could not start ADB thread");
-    return;
+  if (CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kRemoteDebuggingRawUSB)) {
+    AndroidUsbDevice::Enumerate(
+        profile_, rsa_key_.get(),
+        base::Bind(&DevToolsAdbBridge::ReceivedUsbDevices, this, callback));
+  } else {
+    ReceivedUsbDevices(callback, AndroidUsbDevices());
   }
-  scoped_refptr<AdbQueryCommand> command(new AdbQueryCommand(query, callback));
-  adb_thread_->message_loop()->PostTask(FROM_HERE,
-      base::Bind(&AdbQueryCommand::Run, command));
 }
 
 void DevToolsAdbBridge::Attach(const std::string& serial,
@@ -899,12 +893,14 @@
 }
 
 void DevToolsAdbBridge::AddListener(Listener* listener) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   if (listeners_.empty())
     RequestPages();
   listeners_.push_back(listener);
 }
 
 void DevToolsAdbBridge::RemoveListener(Listener* listener) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   Listeners::iterator it =
       std::find(listeners_.begin(), listeners_.end(), listener);
   DCHECK(it != listeners_.end());
@@ -912,28 +908,36 @@
 }
 
 DevToolsAdbBridge::~DevToolsAdbBridge() {
-  DCHECK(listeners_.empty());
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  DCHECK(listeners_.empty());
 }
 
-void DevToolsAdbBridge::ReceivedDevices(const AndroidDevicesCallback& callback,
-                                        int result,
-                                        const std::string& response) {
+void DevToolsAdbBridge::ReceivedUsbDevices(
+    const AndroidDevicesCallback& callback,
+    const AndroidUsbDevices& usb_devices) {
   AndroidDevices devices;
+
 #if defined(DEBUG_DEVTOOLS)
   devices.push_back(new AdbDeviceImpl(""));  // For desktop remote debugging.
 #endif  // defined(DEBUG_DEVTOOLS)
 
-  if (CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kRemoteDebuggingRawUSB)) {
-    AndroidUsbDevices usb_devices;
-    AndroidUsbDevice::Enumerate(profile_, rsa_key_.get(), &usb_devices);
-    for (AndroidUsbDevices::iterator it = usb_devices.begin();
-         it != usb_devices.end(); ++it) {
-      devices.push_back(new UsbDeviceImpl(*it));
-    }
+  for (AndroidUsbDevices::const_iterator it = usb_devices.begin();
+       it != usb_devices.end(); ++it) {
+    devices.push_back(new UsbDeviceImpl(*it));
   }
 
+  AdbClientSocket::AdbQuery(
+      kAdbPort, kHostDevicesCommand,
+      base::Bind(&DevToolsAdbBridge::ReceivedAdbDevices, this, callback,
+                 devices));
+
+}
+
+void DevToolsAdbBridge::ReceivedAdbDevices(
+    const AndroidDevicesCallback& callback,
+    AndroidDevices devices,
+    int result,
+    const std::string& response) {
   if (result != net::OK) {
     callback.Run(devices);
     return;
diff --git a/chrome/browser/devtools/devtools_adb_bridge.h b/chrome/browser/devtools/devtools_adb_bridge.h
index a114e94..f091365 100644
--- a/chrome/browser/devtools/devtools_adb_bridge.h
+++ b/chrome/browser/devtools/devtools_adb_bridge.h
@@ -11,6 +11,7 @@
 #include "base/callback.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
+#include "chrome/browser/devtools/adb/android_usb_device.h"
 #include "components/browser_context_keyed_service/browser_context_keyed_service.h"
 #include "components/browser_context_keyed_service/browser_context_keyed_service_factory.h"
 #include "net/socket/tcp_client_socket.h"
@@ -162,7 +163,7 @@
   explicit DevToolsAdbBridge(Profile* profile);
 
   void EnumerateDevices(const AndroidDevicesCallback& callback);
-  void Query(const std::string query, const Callback& callback);
+
   void Attach(const std::string& serial,
               const std::string& socket,
               const std::string& debug_url,
@@ -184,8 +185,6 @@
   friend class AdbWebSocket;
   friend class AgentHostDelegate;
 
-  virtual ~DevToolsAdbBridge();
-
   class RefCountedAdbThread : public base::RefCounted<RefCountedAdbThread> {
    public:
     static scoped_refptr<RefCountedAdbThread> GetInstance();
@@ -201,9 +200,13 @@
     base::Thread* thread_;
   };
 
-  void ReceivedDevices(const AndroidDevicesCallback& callback,
-                       int result,
-                       const std::string& response);
+  virtual ~DevToolsAdbBridge();
+  void ReceivedUsbDevices(const AndroidDevicesCallback& callback,
+                          const AndroidUsbDevices& usb_devices);
+  void ReceivedAdbDevices(const AndroidDevicesCallback& callback,
+                          AndroidDevices devices,
+                          int result,
+                          const std::string& response);
 
   void RequestPages();
   void ReceivedPages(int result, RemotePages* pages);
diff --git a/chrome/browser/devtools/devtools_file_helper.cc b/chrome/browser/devtools/devtools_file_helper.cc
index cb596d6..5d971f0 100644
--- a/chrome/browser/devtools/devtools_file_helper.cc
+++ b/chrome/browser/devtools/devtools_file_helper.cc
@@ -299,9 +299,18 @@
     const AddFileSystemCallback& callback,
     const ShowInfoBarCallback& show_info_bar_callback,
     const base::FilePath& path) {
+  std::string file_system_path = path.AsUTF8Unsafe();
+
+  const DictionaryValue* file_systems_paths_value =
+      profile_->GetPrefs()->GetDictionary(prefs::kDevToolsFileSystemPaths);
+  if (file_systems_paths_value->HasKey(file_system_path)) {
+    callback.Run(FileSystem());
+    return;
+  }
+
   string16 message = l10n_util::GetStringFUTF16(
       IDS_DEV_TOOLS_CONFIRM_ADD_FILE_SYSTEM_MESSAGE,
-      UTF8ToUTF16(path.AsUTF8Unsafe() + "/"));
+      UTF8ToUTF16(file_system_path + "/"));
   show_info_bar_callback.Run(
       message,
       Bind(&DevToolsFileHelper::AddUserConfirmedFileSystem,
diff --git a/chrome/browser/devtools/devtools_sanity_browsertest.cc b/chrome/browser/devtools/devtools_sanity_browsertest.cc
index 3abe937..4905f6e 100644
--- a/chrome/browser/devtools/devtools_sanity_browsertest.cc
+++ b/chrome/browser/devtools/devtools_sanity_browsertest.cc
@@ -47,6 +47,10 @@
 #include "net/socket/tcp_listen_socket.h"
 #include "net/test/spawned_test_server/spawned_test_server.h"
 
+#if defined(OS_WIN) && defined(USE_ASH)
+#include "base/win/windows_version.h"
+#endif
+
 using content::BrowserThread;
 using content::DevToolsManager;
 using content::DevToolsAgentHost;
@@ -474,12 +478,6 @@
   RunTest("testContentScriptIsPresent", kPageWithContentScript);
 }
 
-// Tests that renderer process native memory is feasible.
-IN_PROC_BROWSER_TEST_F(DevToolsSanityTest,
-                       DISABLED_TestRendererProcessNativeMemorySize) {
-  RunTest("testRendererProcessNativeMemorySize", std::string());
-}
-
 // Tests that scripts are not duplicated after Scripts Panel switch.
 IN_PROC_BROWSER_TEST_F(DevToolsSanityTest,
                        TestNoScriptDuplicatesOnPanelSwitch) {
@@ -597,6 +595,12 @@
 #endif
 // Flakily fails with 25s timeout: http://crbug.com/89845
 IN_PROC_BROWSER_TEST_F(WorkerDevToolsSanityTest, MAYBE_InspectSharedWorker) {
+#if defined(OS_WIN) && defined(USE_ASH)
+  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
+  if (base::win::GetVersion() >= base::win::VERSION_WIN8)
+    return;
+#endif
+
   RunTest("testSharedWorker", kSharedWorkerTestPage);
 }
 
@@ -658,6 +662,12 @@
 };
 
 IN_PROC_BROWSER_TEST_F(RemoteDebuggingTest, RemoteDebugger) {
+#if defined(OS_WIN) && defined(USE_ASH)
+  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
+  if (base::win::GetVersion() >= base::win::VERSION_WIN8)
+    return;
+#endif
+
   ASSERT_TRUE(RunExtensionTest("target_list")) << message_;
 }
 
diff --git a/chrome/browser/download/download_browsertest.cc b/chrome/browser/download/download_browsertest.cc
index 6125d22..b07cba9 100644
--- a/chrome/browser/download/download_browsertest.cc
+++ b/chrome/browser/download/download_browsertest.cc
@@ -65,7 +65,6 @@
 #include "content/public/browser/download_save_info.h"
 #include "content/public/browser/download_url_parameters.h"
 #include "content/public/browser/notification_source.h"
-#include "content/public/browser/plugin_service.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/resource_context.h"
 #include "content/public/browser/web_contents.h"
@@ -83,7 +82,10 @@
 #include "net/test/spawned_test_server/spawned_test_server.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/l10n/l10n_util.h"
-#include "webkit/plugins/npapi/mock_plugin_list.h"
+
+#if defined(OS_WIN) && defined(USE_ASH)
+#include "base/win/windows_version.h"
+#endif
 
 using content::BrowserContext;
 using content::BrowserThread;
@@ -473,6 +475,10 @@
     file_activity_observer_.reset();
   }
 
+  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
+    command_line->AppendSwitch(switches::kDisablePluginsDiscovery);
+  }
+
   // Returning false indicates a failure of the setup, and should be asserted
   // in the caller.
   virtual bool InitialSetup() {
@@ -1850,12 +1856,6 @@
   base::FilePath file(FILE_PATH_LITERAL("downloads/dangerous/dangerous.swf"));
   GURL download_url(URLRequestMockHTTPJob::GetMockUrl(file));
 
-  // Null out plugins so that flash plugin won't interfere with testing.
-#if defined(ENABLE_PLUGINS)
-  webkit::npapi::MockPluginList plugin_list;
-  content::PluginService::GetInstance()->SetPluginListForTesting(&plugin_list);
-#endif
-
   // Download the url and wait until the object has been stored.
   scoped_ptr<content::DownloadTestObserver> download_observer(
       new content::DownloadTestObserverTerminal(
@@ -2776,6 +2776,12 @@
 
 // Verify the multiple downloads infobar.
 IN_PROC_BROWSER_TEST_F(DownloadTest, TestMultipleDownloadsInfobar) {
+#if defined(OS_WIN) && defined(USE_ASH)
+  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
+  if (base::win::GetVersion() >= base::win::VERSION_WIN8)
+    return;
+#endif
+
   ASSERT_TRUE(test_server()->Start());
 
   // Create a downloads observer.
diff --git a/chrome/browser/download/download_crx_util.cc b/chrome/browser/download/download_crx_util.cc
index 1f71a88..06e8b18 100644
--- a/chrome/browser/download/download_crx_util.cc
+++ b/chrome/browser/download/download_crx_util.cc
@@ -16,9 +16,9 @@
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/host_desktop.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "chrome/common/extensions/user_script.h"
 #include "content/public/browser/download_item.h"
 #include "content/public/browser/notification_service.h"
+#include "extensions/common/user_script.h"
 
 using content::BrowserThread;
 using content::DownloadItem;
diff --git a/chrome/browser/download/download_danger_prompt.cc b/chrome/browser/download/download_danger_prompt.cc
index bdd75cc..d75c6cc 100644
--- a/chrome/browser/download/download_danger_prompt.cc
+++ b/chrome/browser/download/download_danger_prompt.cc
@@ -22,7 +22,6 @@
     public TabModalConfirmDialogDelegate {
  public:
   DownloadDangerPromptImpl(content::DownloadItem* item,
-                           content::WebContents* web_contents,
                            bool show_context,
                            const base::Closure& accepted,
                            const base::Closure& canceled);
@@ -63,12 +62,10 @@
 
 DownloadDangerPromptImpl::DownloadDangerPromptImpl(
     content::DownloadItem* download,
-    content::WebContents* web_contents,
     bool show_context,
     const base::Closure& accepted,
     const base::Closure& canceled)
-    : TabModalConfirmDialogDelegate(web_contents),
-      download_(download),
+    : download_(download),
       show_context_(show_context),
       accepted_(accepted),
       canceled_(canceled) {
@@ -175,7 +172,7 @@
     const base::Closure& accepted,
     const base::Closure& canceled) {
   DownloadDangerPromptImpl* prompt = new DownloadDangerPromptImpl(
-      item, web_contents, show_context, accepted, canceled);
+      item, show_context, accepted, canceled);
   // |prompt| will be deleted when the dialog is done.
   TabModalConfirmDialog::Create(prompt, web_contents);
   return prompt;
diff --git a/chrome/browser/download/download_item_model.cc b/chrome/browser/download/download_item_model.cc
index ec11fc0..f8dc3db 100644
--- a/chrome/browser/download/download_item_model.cc
+++ b/chrome/browser/download/download_item_model.cc
@@ -402,28 +402,39 @@
 }
 
 bool DownloadItemModel::ShouldRemoveFromShelfWhenComplete() const {
-  // If the download was already opened automatically, it should be removed.
-  if (download_->GetAutoOpened())
-    return true;
+  switch (download_->GetState()) {
+    case DownloadItem::IN_PROGRESS:
+      // If the download is dangerous or malicious, we should display a warning
+      // on the shelf until the user accepts the download.
+      if (IsDangerous())
+        return false;
 
-  // If the download is interrupted or cancelled, it should not be removed.
-  DownloadItem::DownloadState state = download_->GetState();
-  if (state == DownloadItem::INTERRUPTED || state == DownloadItem::CANCELLED)
-    return false;
+      // If the download is an extension, temporary, or will be opened
+      // automatically, then it should be removed from the shelf on completion.
+      // TODO(asanka): The logic for deciding opening behavior should be in a
+      //               central location. http://crbug.com/167702
+      return (download_crx_util::IsExtensionDownload(*download_) ||
+              download_->IsTemporary() ||
+              download_->GetOpenWhenComplete() ||
+              download_->ShouldOpenFileBasedOnExtension());
 
-  // If the download is dangerous or malicious, we should display a warning on
-  // the shelf until the user accepts the download.
-  if (IsDangerous())
-    return false;
+    case DownloadItem::COMPLETE:
+      // If the download completed, then rely on GetAutoOpened() to check for
+      // opening behavior. This should accurately reflect whether the download
+      // was successfully opened.  Extensions, for example, may fail to open.
+      return download_->GetAutoOpened() || download_->IsTemporary();
 
-  // If the download is an extension, temporary, or will be opened
-  // automatically, then it should be removed from the shelf on completion.
-  // TODO(asanka): The logic for deciding opening behavior should be in a
-  //               central location. http://crbug.com/167702
-  return (download_crx_util::IsExtensionDownload(*download_) ||
-          download_->IsTemporary() ||
-          download_->GetOpenWhenComplete() ||
-          download_->ShouldOpenFileBasedOnExtension());
+    case DownloadItem::CANCELLED:
+    case DownloadItem::INTERRUPTED:
+      // Interrupted or cancelled downloads should remain on the shelf.
+      return false;
+
+    case DownloadItem::MAX_DOWNLOAD_STATE:
+      NOTREACHED();
+  }
+
+  NOTREACHED();
+  return false;
 }
 
 bool DownloadItemModel::ShouldShowDownloadStartedAnimation() const {
diff --git a/chrome/browser/download/download_item_model_unittest.cc b/chrome/browser/download/download_item_model_unittest.cc
index 807a32a..4dbf072 100644
--- a/chrome/browser/download/download_item_model_unittest.cc
+++ b/chrome/browser/download/download_item_model_unittest.cc
@@ -12,6 +12,7 @@
 #include "base/strings/string16.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
+#include "chrome/common/extensions/extension.h"
 #include "content/public/test/mock_download_item.h"
 #include "grit/generated_resources.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -358,30 +359,35 @@
 TEST_F(DownloadItemModelTest, ShouldRemoveFromShelfWhenComplete) {
   const struct TestCase {
     DownloadItem::DownloadState state;
-    bool is_dangerous;
-    bool is_auto_open;  // Either an extension install, temporary, open when
-                        // complete or open based on extension.
+    bool is_dangerous;  // Expectation for IsDangerous().
+    bool is_auto_open;  // Expectation for GetOpenWhenComplete().
+    bool auto_opened;   // Whether the download was successfully
+                        // auto-opened. Expecation for GetAutoOpened().
     bool expected_result;
   } kTestCases[] = {
-    // All the valid combinations of state, is_dangerous and is_auto_open.
+    // All the valid combinations of state, is_dangerous, is_auto_open and
+    // auto_opened.
     //
     //                              .--- Is dangerous.
     //                             |       .--- Auto open or temporary.
-    //                             |      |      .--- Expected result.
-    { DownloadItem::IN_PROGRESS, false, false, false },
-    { DownloadItem::IN_PROGRESS, false, true , true  },
-    { DownloadItem::IN_PROGRESS, true , false, false },
-    { DownloadItem::IN_PROGRESS, true , true , false },
-    { DownloadItem::COMPLETE,    false, false, false },
-    { DownloadItem::COMPLETE,    false, true , true  },
-    { DownloadItem::CANCELLED,   false, false, false },
-    { DownloadItem::CANCELLED,   false, true , false },
-    { DownloadItem::CANCELLED,   true , false, false },
-    { DownloadItem::CANCELLED,   true , true , false },
-    { DownloadItem::INTERRUPTED, false, false, false },
-    { DownloadItem::INTERRUPTED, false, true , false },
-    { DownloadItem::INTERRUPTED, true , false, false },
-    { DownloadItem::INTERRUPTED, true , true , false }
+    //                             |      |      .--- Auto opened.
+    //                             |      |      |      .--- Expected result.
+    { DownloadItem::IN_PROGRESS, false, false, false, false},
+    { DownloadItem::IN_PROGRESS, false, true , false, true },
+    { DownloadItem::IN_PROGRESS, true , false, false, false},
+    { DownloadItem::IN_PROGRESS, true , true , false, false},
+    { DownloadItem::COMPLETE,    false, false, false, false},
+    { DownloadItem::COMPLETE,    false, true , false, false},
+    { DownloadItem::COMPLETE,    false, false, true , true },
+    { DownloadItem::COMPLETE,    false, true , true , true },
+    { DownloadItem::CANCELLED,   false, false, false, false},
+    { DownloadItem::CANCELLED,   false, true , false, false},
+    { DownloadItem::CANCELLED,   true , false, false, false},
+    { DownloadItem::CANCELLED,   true , true , false, false},
+    { DownloadItem::INTERRUPTED, false, false, false, false},
+    { DownloadItem::INTERRUPTED, false, true , false, false},
+    { DownloadItem::INTERRUPTED, true , false, false, false},
+    { DownloadItem::INTERRUPTED, true , true , false, false}
   };
 
   SetupDownloadItemDefaults();
@@ -394,6 +400,8 @@
         .WillRepeatedly(Return(test_case.state));
     EXPECT_CALL(item(), IsDangerous())
         .WillRepeatedly(Return(test_case.is_dangerous));
+    EXPECT_CALL(item(), GetAutoOpened())
+        .WillRepeatedly(Return(test_case.auto_opened));
 
     EXPECT_EQ(test_case.expected_result,
               model().ShouldRemoveFromShelfWhenComplete())
diff --git a/chrome/browser/download/download_request_infobar_delegate.h b/chrome/browser/download/download_request_infobar_delegate.h
index 815e3ca..410f91f 100644
--- a/chrome/browser/download/download_request_infobar_delegate.h
+++ b/chrome/browser/download/download_request_infobar_delegate.h
@@ -23,15 +23,13 @@
       base::WeakPtr<DownloadRequestLimiter::TabDownloadState> host)>
     FakeCreateCallback;
 
+  virtual ~DownloadRequestInfoBarDelegate();
+
   // Creates a download request delegate and adds it to |infobar_service|.
   static void Create(
       InfoBarService* infobar_service,
       base::WeakPtr<DownloadRequestLimiter::TabDownloadState> host);
 
-  static void SetCallbackForTesting(FakeCreateCallback* callback);
-
-  virtual ~DownloadRequestInfoBarDelegate();
-
 #if defined(UNIT_TEST)
   static scoped_ptr<DownloadRequestInfoBarDelegate> Create(
       base::WeakPtr<DownloadRequestLimiter::TabDownloadState> host) {
@@ -40,6 +38,8 @@
   }
 #endif
 
+  static void SetCallbackForTesting(FakeCreateCallback* callback);
+
  private:
   static FakeCreateCallback* callback_;
 
diff --git a/chrome/browser/download/download_shelf_unittest.cc b/chrome/browser/download/download_shelf_unittest.cc
index 2280173..3a16773 100644
--- a/chrome/browser/download/download_shelf_unittest.cc
+++ b/chrome/browser/download/download_shelf_unittest.cc
@@ -151,6 +151,8 @@
 
   EXPECT_CALL(*download_item(), GetState())
       .WillRepeatedly(Return(DownloadItem::COMPLETE));
+  EXPECT_CALL(*download_item(), GetAutoOpened())
+      .WillRepeatedly(Return(true));
 
   base::RunLoop run_loop;
   run_loop.RunUntilIdle();
diff --git a/chrome/browser/download/download_util.h b/chrome/browser/download/download_util.h
index e5e9a60..7900868 100644
--- a/chrome/browser/download/download_util.h
+++ b/chrome/browser/download/download_util.h
@@ -183,6 +183,9 @@
   // The download was initiated by the plugin installer.
   INITIATED_BY_PLUGIN_INSTALLER,
 
+  // The download was initiated by the PDF plugin..
+  INITIATED_BY_PDF_SAVE,
+
   CHROME_DOWNLOAD_SOURCE_LAST_ENTRY,
 };
 
diff --git a/chrome/browser/extensions/active_tab_permission_granter.cc b/chrome/browser/extensions/active_tab_permission_granter.cc
index 97440e2..312a6c3 100644
--- a/chrome/browser/extensions/active_tab_permission_granter.cc
+++ b/chrome/browser/extensions/active_tab_permission_granter.cc
@@ -13,13 +13,13 @@
 #include "chrome/common/extensions/extension_messages.h"
 #include "chrome/common/extensions/permissions/permission_set.h"
 #include "chrome/common/extensions/permissions/permissions_data.h"
-#include "chrome/common/extensions/user_script.h"
-#include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/navigation_details.h"
+#include "content/public/browser/navigation_entry.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/web_contents.h"
+#include "extensions/common/user_script.h"
 
 using content::RenderProcessHost;
 using content::WebContentsObserver;
diff --git a/chrome/browser/extensions/activity_log/activity_actions.cc b/chrome/browser/extensions/activity_log/activity_actions.cc
index 2e87663..93e9b68 100644
--- a/chrome/browser/extensions/activity_log/activity_actions.cc
+++ b/chrome/browser/extensions/activity_log/activity_actions.cc
@@ -3,18 +3,30 @@
 // found in the LICENSE file.
 
 #include <string>
+#include "base/json/json_string_value_serializer.h"
 #include "base/logging.h"
 #include "base/strings/stringprintf.h"
 #include "chrome/browser/extensions/activity_log/activity_actions.h"
 
+namespace {
+
+std::string Serialize(const base::Value* value) {
+  std::string value_as_text;
+  if (!value) {
+    value_as_text = "null";
+  } else {
+    JSONStringValueSerializer serializer(&value_as_text);
+    serializer.SerializeAndOmitBinaryValues(*value);
+  }
+  return value_as_text;
+}
+
+}  // namespace
+
 namespace extensions {
 
 using api::activity_log_private::ExtensionActivity;
 
-const char* Action::kTableBasicFields =
-    "extension_id LONGVARCHAR NOT NULL, "
-    "time INTEGER NOT NULL";
-
 Action::Action(const std::string& extension_id,
                const base::Time& time,
                ExtensionActivity::ActivityType activity_type)
@@ -22,40 +34,83 @@
       time_(time),
       activity_type_(activity_type) {}
 
-// static
-bool Action::InitializeTableInternal(sql::Connection* db,
-                                     const char* table_name,
-                                     const char* content_fields[],
-                                     const char* field_types[],
-                                     const int num_content_fields) {
-  if (!db->DoesTableExist(table_name)) {
-    std::string table_creator = base::StringPrintf(
-        "CREATE TABLE %s (%s", table_name, kTableBasicFields);
-    for (int i = 0; i < num_content_fields; i++) {
-      table_creator += base::StringPrintf(", %s %s",
-                                          content_fields[i],
-                                          field_types[i]);
-    }
-    table_creator += ")";
-    if (!db->Execute(table_creator.c_str()))
-      return false;
-  } else {
-    // In case we ever want to add new fields, this initializes them to be
-    // empty strings.
-    for (int i = 0; i < num_content_fields; i++) {
-      if (!db->DoesColumnExist(table_name, content_fields[i])) {
-        std::string table_updater = base::StringPrintf(
-            "ALTER TABLE %s ADD COLUMN %s %s; ",
-             table_name,
-             content_fields[i],
-             field_types[i]);
-        if (!db->Execute(table_updater.c_str()))
-          return false;
-      }
-    }
-  }
+WatchdogAction::WatchdogAction(const std::string& extension_id,
+                               const base::Time& time,
+                               const ActionType action_type,
+                               const std::string& api_name,
+                               scoped_ptr<ListValue> args,
+                               const GURL& page_url,
+                               const GURL& arg_url,
+                               scoped_ptr<DictionaryValue> other)
+    : Action(extension_id, time, ExtensionActivity::ACTIVITY_TYPE_CHROME),
+      action_type_(action_type),
+      api_name_(api_name),
+      args_(args.Pass()),
+      page_url_(page_url),
+      arg_url_(arg_url),
+      other_(other.Pass()) {}
+
+WatchdogAction::~WatchdogAction() {}
+
+bool WatchdogAction::Record(sql::Connection* db) {
+  // This methods isn't used and will go away entirely soon once database
+  // writing moves to the policy objects.
+  NOTREACHED();
   return true;
 }
 
-}  // namespace extensions
+scoped_ptr<api::activity_log_private::ExtensionActivity>
+WatchdogAction::ConvertToExtensionActivity() {
+  scoped_ptr<api::activity_log_private::ExtensionActivity> result;
+  return result.Pass();
+}
 
+std::string WatchdogAction::PrintForDebug() {
+  std::string result = "ID=" + extension_id() + " CATEGORY=";
+  switch (action_type_) {
+    case ACTION_API_CALL:
+      result += "api_call";
+      break;
+    case ACTION_API_EVENT:
+      result += "api_event_callback";
+      break;
+    case ACTION_WEB_REQUEST:
+      result += "webrequest";
+      break;
+    case ACTION_CONTENT_SCRIPT:
+      result += "content_script";
+      break;
+    case ACTION_API_BLOCKED:
+      result += "api_blocked";
+      break;
+    case ACTION_DOM_EVENT:
+      result += "dom_event";
+      break;
+    case ACTION_DOM_XHR:
+      result += "dom_xhr";
+      break;
+    case ACTION_DOM_ACCESS:
+      result += "dom_access";
+      break;
+    default:
+      result += base::StringPrintf("type%d", static_cast<int>(action_type_));
+  }
+
+  result += " API=" + api_name_;
+  if (args_.get()) {
+    result += " ARGS=" + Serialize(args_.get());
+  }
+  if (page_url_.is_valid()) {
+    result += " PAGE_URL=" + page_url_.spec();
+  }
+  if (arg_url_.is_valid()) {
+    result += " ARG_URL=" + arg_url_.spec();
+  }
+  if (other_.get()) {
+    result += " OTHER=" + Serialize(other_.get());
+  }
+
+  return result;
+}
+
+}  // namespace extensions
diff --git a/chrome/browser/extensions/activity_log/activity_actions.h b/chrome/browser/extensions/activity_log/activity_actions.h
index 2a5d636..22a242b 100644
--- a/chrome/browser/extensions/activity_log/activity_actions.h
+++ b/chrome/browser/extensions/activity_log/activity_actions.h
@@ -13,6 +13,7 @@
 #include "sql/connection.h"
 #include "sql/statement.h"
 #include "sql/transaction.h"
+#include "url/gurl.h"
 
 namespace extensions {
 
@@ -20,10 +21,18 @@
 // the activity log.
 class Action : public base::RefCountedThreadSafe<Action> {
  public:
-  static const char* kTableBasicFields;
-
-  // Initialize the table for a given action type.
-  static bool InitializeTableInternal(sql::Connection* db);
+  // Types of log entries that can be stored.  The numeric values are stored in
+  // the database, so keep them stable.  Append values only.
+  enum ActionType {
+    ACTION_API_CALL = 0,
+    ACTION_API_EVENT = 1,
+    ACTION_API_BLOCKED = 2,
+    ACTION_CONTENT_SCRIPT = 3,
+    ACTION_DOM_ACCESS = 4,
+    ACTION_DOM_EVENT = 5,
+    ACTION_DOM_XHR = 6,
+    ACTION_WEB_REQUEST = 7,
+  };
 
   // Record the action in the database.
   virtual bool Record(sql::Connection* db) = 0;
@@ -46,17 +55,6 @@
          api::activity_log_private::ExtensionActivity::ActivityType type);
   virtual ~Action() {}
 
-  // Initialize the table for a given action type.
-  // The content_fields array should list the names of all of the columns in
-  // the database. The field_types should specify the types of the corresponding
-  // columns (e.g., INTEGER or LONGVARCHAR). There should be the same number of
-  // field_types as content_fields, since the two arrays should correspond.
-  static bool InitializeTableInternal(sql::Connection* db,
-                                      const char* table_name,
-                                      const char* content_fields[],
-                                      const char* field_types[],
-                                      const int num_content_fields);
-
  private:
   friend class base::RefCountedThreadSafe<Action>;
 
@@ -67,6 +65,38 @@
   DISALLOW_COPY_AND_ASSIGN(Action);
 };
 
+// TODO(mvrable): This is a temporary class used to represent Actions which
+// have been loaded from the SQLite database.  Soon the entire Action hierarchy
+// will be flattened out as the type-specific classes are eliminated, at which
+// time some of the logic here will be moved.
+class WatchdogAction : public Action {
+ public:
+  WatchdogAction(const std::string& extension_id,
+                 const base::Time& time,
+                 const ActionType action_type,
+                 const std::string& api_name,  // full method name
+                 scoped_ptr<ListValue> args,  // the argument list
+                 const GURL& page_url,  // page the action occurred on
+                 const GURL& arg_url,  // URL extracted from the argument list
+                 scoped_ptr<DictionaryValue> other);  // any extra logging info
+
+  virtual bool Record(sql::Connection* db) OVERRIDE;
+  virtual scoped_ptr<api::activity_log_private::ExtensionActivity>
+      ConvertToExtensionActivity() OVERRIDE;
+  virtual std::string PrintForDebug() OVERRIDE;
+
+ protected:
+  virtual ~WatchdogAction();
+
+ private:
+  ActionType action_type_;
+  std::string api_name_;
+  scoped_ptr<ListValue> args_;
+  GURL page_url_;
+  GURL arg_url_;
+  scoped_ptr<DictionaryValue> other_;
+};
+
 }  // namespace extensions
 
 #endif  // CHROME_BROWSER_EXTENSIONS_ACTIVITY_LOG_ACTIVITY_ACTIONS_H_
diff --git a/chrome/browser/extensions/activity_log/activity_database.cc b/chrome/browser/extensions/activity_log/activity_database.cc
index 9770937..1a644b8 100644
--- a/chrome/browser/extensions/activity_log/activity_database.cc
+++ b/chrome/browser/extensions/activity_log/activity_database.cc
@@ -4,6 +4,7 @@
 
 #include <string>
 #include "base/command_line.h"
+#include "base/json/json_reader.h"
 #include "base/logging.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
@@ -12,6 +13,7 @@
 #include "base/time/clock.h"
 #include "base/time/time.h"
 #include "chrome/browser/extensions/activity_log/activity_database.h"
+#include "chrome/browser/extensions/activity_log/fullstream_ui_policy.h"
 #include "chrome/common/chrome_switches.h"
 #include "sql/error_delegate_util.h"
 #include "sql/transaction.h"
@@ -160,44 +162,45 @@
       early_bound = early_time.ToInternalValue();
       late_bound = late_time.ToInternalValue();
   }
-  // Get the DOMActions.
-  std::string dom_str = base::StringPrintf("SELECT * FROM %s "
-                                           "WHERE extension_id=? AND "
-                                           "time>? AND time<=?",
-                                           DOMAction::kTableName);
-  sql::Statement dom_statement(db_.GetCachedStatement(SQL_FROM_HERE,
-                                                      dom_str.c_str()));
-  dom_statement.BindString(0, extension_id);
-  dom_statement.BindInt64(1, early_bound);
-  dom_statement.BindInt64(2, late_bound);
-  while (dom_statement.is_valid() && dom_statement.Step()) {
-    actions->push_back(new DOMAction(dom_statement));
-  }
-  // Get the APIActions.
-  std::string api_str = base::StringPrintf("SELECT * FROM %s "
-                                           "WHERE extension_id=? AND "
-                                           "time>? AND time<=?",
-                                            APIAction::kTableName);
-  sql::Statement api_statement(db_.GetCachedStatement(SQL_FROM_HERE,
-                                                      api_str.c_str()));
-  api_statement.BindString(0, extension_id);
-  api_statement.BindInt64(1, early_bound);
-  api_statement.BindInt64(2, late_bound);
-  while (api_statement.is_valid() && api_statement.Step()) {
-    actions->push_back(new APIAction(api_statement));
-  }
-  // Get the BlockedActions.
-  std::string blocked_str = base::StringPrintf("SELECT * FROM %s "
-                                               "WHERE extension_id=? AND "
-                                               "time>? AND time<=?",
-                                               BlockedAction::kTableName);
-  sql::Statement blocked_statement(db_.GetCachedStatement(SQL_FROM_HERE,
-                                                          blocked_str.c_str()));
-  blocked_statement.BindString(0, extension_id);
-  blocked_statement.BindInt64(1, early_bound);
-  blocked_statement.BindInt64(2, late_bound);
-  while (blocked_statement.is_valid() && blocked_statement.Step()) {
-    actions->push_back(new BlockedAction(blocked_statement));
+  std::string query_str = base::StringPrintf(
+      "SELECT time, action_type, api_name, args, page_url, arg_url, other "
+      "FROM %s WHERE extension_id=? AND time>? AND time<=?",
+      FullStreamUIPolicy::kTableName);
+  sql::Statement query(db_.GetCachedStatement(SQL_FROM_HERE,
+                                              query_str.c_str()));
+  query.BindString(0, extension_id);
+  query.BindInt64(1, early_bound);
+  query.BindInt64(2, late_bound);
+  while (query.is_valid() && query.Step()) {
+    scoped_ptr<Value> raw_value(base::JSONReader::Read(query.ColumnString(3)));
+    scoped_ptr<ListValue> args;
+    if (raw_value && raw_value->IsType(Value::TYPE_LIST)) {
+      args.reset(static_cast<ListValue*>(raw_value.release()));
+    } else {
+      args.reset(new ListValue());
+    }
+
+    GURL page_url(query.ColumnString(4));
+    GURL arg_url(query.ColumnString(5));
+
+    raw_value.reset(base::JSONReader::Read(query.ColumnString(6)));
+    scoped_ptr<DictionaryValue> other;
+    if (raw_value && raw_value->IsType(Value::TYPE_DICTIONARY)) {
+      other.reset(static_cast<DictionaryValue*>(raw_value.release()));
+    } else {
+      other.reset(new DictionaryValue());
+    }
+
+    scoped_refptr<WatchdogAction> action =
+        new WatchdogAction(extension_id,
+                           base::Time::FromInternalValue(query.ColumnInt64(0)),
+                           static_cast<Action::ActionType>(query.ColumnInt(1)),
+                           query.ColumnString(2),
+                           args.Pass(),
+                           page_url,
+                           arg_url,
+                           other.Pass());
+    actions->push_back(action);
   }
   // Sort by time (from newest to oldest).
   std::sort(actions->begin(), actions->end(), SortActionsByTime);
@@ -260,4 +263,40 @@
                &ActivityDatabase::RecordBatchedActionsWhileTesting);
 }
 
+// static
+bool ActivityDatabase::InitializeTable(sql::Connection* db,
+                                       const char* table_name,
+                                       const char* content_fields[],
+                                       const char* field_types[],
+                                       const int num_content_fields) {
+  if (!db->DoesTableExist(table_name)) {
+    std::string table_creator =
+        base::StringPrintf("CREATE TABLE %s (", table_name);
+    for (int i = 0; i < num_content_fields; i++) {
+      table_creator += base::StringPrintf("%s%s %s",
+                                          i == 0 ? "" : ", ",
+                                          content_fields[i],
+                                          field_types[i]);
+    }
+    table_creator += ")";
+    if (!db->Execute(table_creator.c_str()))
+      return false;
+  } else {
+    // In case we ever want to add new fields, this initializes them to be
+    // empty strings.
+    for (int i = 0; i < num_content_fields; i++) {
+      if (!db->DoesColumnExist(table_name, content_fields[i])) {
+        std::string table_updater = base::StringPrintf(
+            "ALTER TABLE %s ADD COLUMN %s %s; ",
+             table_name,
+             content_fields[i],
+             field_types[i]);
+        if (!db->Execute(table_updater.c_str()))
+          return false;
+      }
+    }
+  }
+  return true;
+}
+
 }  // namespace extensions
diff --git a/chrome/browser/extensions/activity_log/activity_database.h b/chrome/browser/extensions/activity_log/activity_database.h
index e646840..6c3c554 100644
--- a/chrome/browser/extensions/activity_log/activity_database.h
+++ b/chrome/browser/extensions/activity_log/activity_database.h
@@ -97,18 +97,9 @@
   // update the database schema if needed.
   void Init(const base::FilePath& db_name);
 
-  // The ActivityLog should call this to kill the ActivityDatabase.
+  // An ActivityLogPolicy should call this to kill the ActivityDatabase.
   void Close();
 
-  // Record a DOMAction in the database.
-  void RecordDOMAction(scoped_refptr<DOMAction> action);
-
-  // Record an APIAction in the database.
-  void RecordAPIAction(scoped_refptr<APIAction> action);
-
-  // Record a BlockedAction in the database.
-  void RecordBlockedAction(scoped_refptr<BlockedAction> action);
-
   // Record an Action in the database.
   void RecordAction(scoped_refptr<Action> action);
 
@@ -125,19 +116,27 @@
 
   bool is_db_valid() const { return valid_db_; }
 
+  // A helper method for initializing or upgrading a database table.  The
+  // content_fields array should list the names of all of the columns in the
+  // database. The field_types should specify the types of the corresponding
+  // columns (e.g., INTEGER or LONGVARCHAR). There should be the same number of
+  // field_types as content_fields, since the two arrays should correspond.
+  static bool InitializeTable(sql::Connection* db,
+                              const char* table_name,
+                              const char* content_fields[],
+                              const char* field_types[],
+                              const int num_content_fields);
+
  private:
   // This should never be invoked by another class. Use Close() to order a
   // suicide.
   virtual ~ActivityDatabase();
 
-  // Used by the Init() method as a convenience for handling a failied
-  // database initialization attempt. Prints an error and puts us in the soft
-  // failure state.
+  // Used by the Init() method as a convenience for handling a failed database
+  // initialization attempt. Prints an error and puts us in the soft failure
+  // state.
   void LogInitFailure();
 
-  sql::InitStatus InitializeTable(const char* table_name,
-                                  const char* table_structure);
-
   // When we're in batched mode (which is on by default), we write to the db
   // every X minutes instead of on every API call. This prevents the annoyance
   // of writing to disk multiple times a second.
diff --git a/chrome/browser/extensions/activity_log/activity_database_unittest.cc b/chrome/browser/extensions/activity_log/activity_database_unittest.cc
index 3fd040bf..1add2ff 100644
--- a/chrome/browser/extensions/activity_log/activity_database_unittest.cc
+++ b/chrome/browser/extensions/activity_log/activity_database_unittest.cc
@@ -14,6 +14,7 @@
 #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"
+#include "chrome/browser/extensions/activity_log/fullstream_ui_policy.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/test_extension_system.h"
 #include "chrome/common/chrome_constants.h"
@@ -47,10 +48,12 @@
 
  protected:
   virtual bool OnDatabaseInit(sql::Connection* db) OVERRIDE {
-    if (!DOMAction::InitializeTable(db)) return false;
-    if (!APIAction::InitializeTable(db)) return false;
-    if (!BlockedAction::InitializeTable(db)) return false;
-    return true;
+    return ActivityDatabase::InitializeTable(
+        db,
+        FullStreamUIPolicy::kTableName,
+        FullStreamUIPolicy::kTableContentFields,
+        FullStreamUIPolicy::kTableFieldTypes,
+        FullStreamUIPolicy::kTableFieldCount);
   }
 
   // Called by ActivityDatabase just before the ActivityDatabase object is
@@ -112,9 +115,7 @@
 
   sql::Connection db;
   ASSERT_TRUE(db.Open(db_file));
-  ASSERT_TRUE(db.DoesTableExist(DOMAction::kTableName));
-  ASSERT_TRUE(db.DoesTableExist(APIAction::kTableName));
-  ASSERT_TRUE(db.DoesTableExist(BlockedAction::kTableName));
+  ASSERT_TRUE(db.DoesTableExist(FullStreamUIPolicy::kTableName));
   db.Close();
 }
 
@@ -128,12 +129,15 @@
 
   ActivityDatabase* activity_db = OpenDatabase(db_file);
   activity_db->SetBatchModeForTesting(false);
+  base::ListValue args_list;
+  args_list.AppendString("woof");
   scoped_refptr<APIAction> action = new APIAction(
       "punky",
       base::Time::Now(),
       APIAction::CALL,
       "brewster",
       "woof",
+      args_list,
       "extra");
   activity_db->RecordAction(action);
   activity_db->Close();
@@ -141,15 +145,15 @@
   sql::Connection db;
   ASSERT_TRUE(db.Open(db_file));
 
-  ASSERT_TRUE(db.DoesTableExist(APIAction::kTableName));
+  ASSERT_TRUE(db.DoesTableExist(FullStreamUIPolicy::kTableName));
   std::string sql_str = "SELECT * FROM " +
-      std::string(APIAction::kTableName);
+      std::string(FullStreamUIPolicy::kTableName);
   sql::Statement statement(db.GetUniqueStatement(sql_str.c_str()));
   ASSERT_TRUE(statement.Step());
   ASSERT_EQ("punky", statement.ColumnString(0));
-  ASSERT_EQ(0, statement.ColumnInt(2));
+  ASSERT_EQ(static_cast<int>(Action::ACTION_API_CALL), statement.ColumnInt(2));
   ASSERT_EQ("brewster", statement.ColumnString(3));
-  ASSERT_EQ("woof", statement.ColumnString(4));
+  ASSERT_EQ("[\"woof\"]", statement.ColumnString(4));
 }
 
 // Check that DOM actions are recorded in the db.
@@ -177,22 +181,26 @@
   sql::Connection db;
   ASSERT_TRUE(db.Open(db_file));
 
-  ASSERT_TRUE(db.DoesTableExist(APIAction::kTableName));
+  ASSERT_TRUE(db.DoesTableExist(FullStreamUIPolicy::kTableName));
   std::string sql_str = "SELECT * FROM " +
-      std::string(DOMAction::kTableName);
+      std::string(FullStreamUIPolicy::kTableName);
   sql::Statement statement(db.GetUniqueStatement(sql_str.c_str()));
   ASSERT_TRUE(statement.Step());
   ASSERT_EQ("punky", statement.ColumnString(0));
-  ASSERT_EQ(DomActionType::MODIFIED, statement.ColumnInt(2));
-  ASSERT_EQ("http://www.google.com", statement.ColumnString(3));
+  ASSERT_EQ(static_cast<int>(Action::ACTION_DOM_ACCESS),
+            statement.ColumnInt(2));
+  // TODO(mvrable): This test doesn't work properly, due to crbug.com/260784
+  // This will be fixed when URL sanitization is moved into the activity log
+  // policies in some upcoming code refactoring.
   if (CommandLine::ForCurrentProcess()->HasSwitch(
       switches::kEnableExtensionActivityLogTesting))
-    ASSERT_EQ("/foo?bar", statement.ColumnString(4));
+    ASSERT_EQ("http://www.google.com/foo?bar", statement.ColumnString(5));
   else
-    ASSERT_EQ("/foo", statement.ColumnString(4));
-  ASSERT_EQ("lets", statement.ColumnString(6));
-  ASSERT_EQ("vamoose", statement.ColumnString(7));
-  ASSERT_EQ("extra", statement.ColumnString(8));
+    ASSERT_EQ("http://www.google.com/foo", statement.ColumnString(5));
+  ASSERT_EQ("lets", statement.ColumnString(3));
+  ASSERT_EQ("[\"vamoose\"]", statement.ColumnString(4));
+  ASSERT_EQ("{\"dom_verb\":6,\"extra\":\"extra\",\"page_title\":\"\"}",
+            statement.ColumnString(7));
 }
 
 // Check that blocked actions are recorded in the db.
@@ -217,16 +225,17 @@
   sql::Connection db;
   ASSERT_TRUE(db.Open(db_file));
 
-  ASSERT_TRUE(db.DoesTableExist(BlockedAction::kTableName));
+  ASSERT_TRUE(db.DoesTableExist(FullStreamUIPolicy::kTableName));
   std::string sql_str = "SELECT * FROM " +
-      std::string(BlockedAction::kTableName);
+      std::string(FullStreamUIPolicy::kTableName);
   sql::Statement statement(db.GetUniqueStatement(sql_str.c_str()));
   ASSERT_TRUE(statement.Step());
   ASSERT_EQ("punky", statement.ColumnString(0));
-  ASSERT_EQ("do.evilThings", statement.ColumnString(2));
-  ASSERT_EQ("1, 2", statement.ColumnString(3));
-  ASSERT_EQ(1, statement.ColumnInt(4));
-  ASSERT_EQ("extra", statement.ColumnString(5));
+  ASSERT_EQ(static_cast<int>(Action::ACTION_API_BLOCKED),
+            statement.ColumnInt(2));
+  ASSERT_EQ("do.evilThings", statement.ColumnString(3));
+  ASSERT_EQ("1, 2", statement.ColumnString(4));
+  ASSERT_EQ("{\"reason\":1}", statement.ColumnString(7));
 }
 
 // Check that we can read back recent actions in the db.
@@ -245,12 +254,15 @@
 
   // Record some actions
   ActivityDatabase* activity_db = OpenDatabase(db_file);
+  base::ListValue args_list;
+  args_list.AppendString("woof");
   scoped_refptr<APIAction> api_action = new APIAction(
       "punky",
       mock_clock.Now() - base::TimeDelta::FromMinutes(40),
       APIAction::CALL,
       "brewster",
       "woof",
+      args_list,
       "extra");
   scoped_refptr<DOMAction> dom_action = new DOMAction(
       "punky",
@@ -275,9 +287,12 @@
   activity_db->RecordAction(extra_dom_action);
 
   // Read them back
-  std::string api_print = "ID: punky, CATEGORY: call, "
-      "API: brewster, ARGS: woof";
-  std::string dom_print = "DOM API CALL: lets, ARGS: vamoose, VERB: modified";
+  std::string api_print =
+      "ID=punky CATEGORY=api_call API=brewster ARGS=[\"woof\"] OTHER={}";
+  std::string dom_print =
+      "ID=punky CATEGORY=dom_access API=lets ARGS=[\"vamoose\"] "
+      "PAGE_URL=http://www.google.com/ "
+      "OTHER={\"dom_verb\":6,\"extra\":\"extra\",\"page_title\":\"\"}";
   scoped_ptr<std::vector<scoped_refptr<Action> > > actions =
       activity_db->GetActions("punky", 0);
   ASSERT_EQ(2, static_cast<int>(actions->size()));
@@ -303,6 +318,8 @@
 
   // Record some actions
   ActivityDatabase* activity_db = OpenDatabase(db_file);
+  base::ListValue args_list;
+  args_list.AppendString("woof");
   scoped_refptr<APIAction> api_action = new APIAction(
       "punky",
       mock_clock.Now() - base::TimeDelta::FromDays(3)
@@ -310,6 +327,7 @@
       APIAction::CALL,
       "brewster",
       "woof",
+      args_list,
       "extra");
   scoped_refptr<DOMAction> dom_action = new DOMAction(
       "punky",
@@ -344,9 +362,12 @@
   activity_db->RecordAction(tooold_dom_action);
 
   // Read them back
-  std::string api_print = "ID: punky, CATEGORY: call, "
-      "API: brewster, ARGS: woof";
-  std::string dom_print = "DOM API CALL: lets, ARGS: vamoose, VERB: modified";
+  std::string api_print =
+      "ID=punky CATEGORY=api_call API=brewster ARGS=[\"woof\"] OTHER={}";
+  std::string dom_print =
+      "ID=punky CATEGORY=dom_access API=lets ARGS=[\"vamoose\"] "
+      "PAGE_URL=http://www.google.com/ "
+      "OTHER={\"dom_verb\":6,\"extra\":\"extra\",\"page_title\":\"\"}";
   scoped_ptr<std::vector<scoped_refptr<Action> > > actions =
       activity_db->GetActions("punky", 3);
   ASSERT_EQ(2, static_cast<int>(actions->size()));
@@ -373,12 +394,15 @@
   ActivityDatabase* activity_db = OpenDatabase(db_file);
   activity_db->SetBatchModeForTesting(false);
   activity_db->SetClockForTesting(&mock_clock);
+  base::ListValue args_list;
+  args_list.AppendString("woof");
   scoped_refptr<APIAction> api_action = new APIAction(
       "punky",
       mock_clock.Now() - base::TimeDelta::FromMinutes(40),
       APIAction::CALL,
       "brewster",
       "woof",
+      args_list,
       "extra");
   activity_db->RecordAction(api_action);
 
@@ -405,12 +429,15 @@
   ActivityDatabase* activity_db = OpenDatabase(db_file);
   activity_db->SetBatchModeForTesting(true);
   activity_db->SetClockForTesting(&mock_clock);
+  base::ListValue args_list;
+  args_list.AppendString("woof");
   scoped_refptr<APIAction> api_action = new APIAction(
       "punky",
       mock_clock.Now() - base::TimeDelta::FromMinutes(40),
       APIAction::CALL,
       "brewster",
       "woof",
+      args_list,
       "extra");
   activity_db->RecordAction(api_action);
 
@@ -439,12 +466,15 @@
 
   ActivityDatabase* activity_db =
       new ActivityDatabase(new ActivityDatabaseTestPolicy());
+  base::ListValue args_list;
+  args_list.AppendString("woof");
   scoped_refptr<APIAction> action = new APIAction(
       "punky",
       base::Time::Now(),
       APIAction::CALL,
       "brewster",
       "woooof",
+      args_list,
       "extra");
   activity_db->RecordAction(action);
   activity_db->Close();
diff --git a/chrome/browser/extensions/activity_log/activity_log.cc b/chrome/browser/extensions/activity_log/activity_log.cc
index 7eac24f..4233e12 100644
--- a/chrome/browser/extensions/activity_log/activity_log.cc
+++ b/chrome/browser/extensions/activity_log/activity_log.cc
@@ -289,6 +289,7 @@
         type,
         api_call,
         MakeArgList(args),
+        *args,
         extra);
 
     observers_->Notify(&Observer::OnExtensionActivity, action);
diff --git a/chrome/browser/extensions/activity_log/activity_log.h b/chrome/browser/extensions/activity_log/activity_log.h
index 2a4e491..19813c2 100644
--- a/chrome/browser/extensions/activity_log/activity_log.h
+++ b/chrome/browser/extensions/activity_log/activity_log.h
@@ -17,6 +17,7 @@
 #include "chrome/browser/extensions/activity_log/activity_actions.h"
 #include "chrome/browser/extensions/activity_log/activity_database.h"
 #include "chrome/browser/extensions/activity_log/activity_log_policy.h"
+#include "chrome/browser/extensions/activity_log/api_actions.h"
 #include "chrome/browser/extensions/install_observer.h"
 #include "chrome/browser/extensions/install_tracker.h"
 #include "chrome/browser/extensions/tab_helper.h"
diff --git a/chrome/browser/extensions/activity_log/activity_log_browsertest.cc b/chrome/browser/extensions/activity_log/activity_log_browsertest.cc
index 6bb158f..db573c1 100644
--- a/chrome/browser/extensions/activity_log/activity_log_browsertest.cc
+++ b/chrome/browser/extensions/activity_log/activity_log_browsertest.cc
@@ -34,7 +34,9 @@
                                     switches::kPrerenderModeSwitchValueEnabled);
   }
 
-  static void Prerender_Arguments(int port,
+  static void Prerender_Arguments(
+      const std::string& extension_id,
+      int port,
       scoped_ptr<std::vector<scoped_refptr<Action> > > i) {
     // This is to exit RunLoop (base::MessageLoop::current()->Run()) below
     base::MessageLoop::current()->PostTask(
@@ -44,9 +46,11 @@
     scoped_refptr<Action> last = i->front();
 
     std::string args = base::StringPrintf(
-        "Injected scripts (\"/google_cs.js \") "
-        "onto http://www.google.com.bo:%d/test.html (prerender)",
-        port);
+        "ID=%s CATEGORY=content_script API= ARGS=[\"\\\"/google_cs.js \\\"\"] "
+        "PAGE_URL=http://www.google.com.bo:%d/test.html "
+        "OTHER={\"dom_verb\":3,\"extra\":\"(prerender)\",\"page_title\":\"www."
+        "google.com.bo:%d/test.html\"}",
+        extension_id.c_str(), port, port);
     // TODO: Replace PrintForDebug with field testing
     // when this feature will be available
     ASSERT_EQ(args, last->PrintForDebug());
@@ -91,14 +95,14 @@
   scoped_ptr<prerender::PrerenderHandle> prerender_handle(
       prerender_manager->AddPrerenderFromLocalPredictor(
           url,
-          web_contents->GetController().GetSessionStorageNamespace(),
+          web_contents->GetController().GetDefaultSessionStorageNamespace(),
           kSize));
 
   page_observer.Wait();
 
   activity_log->GetActions(
       ext->id(), 0, base::Bind(
-          ActivityLogPrerenderTest::Prerender_Arguments, port));
+          ActivityLogPrerenderTest::Prerender_Arguments, ext->id(), port));
 
   // Allow invocation of Prerender_Arguments
   base::MessageLoop::current()->Run();
diff --git a/chrome/browser/extensions/activity_log/activity_log_unittest.cc b/chrome/browser/extensions/activity_log/activity_log_unittest.cc
index e9f2c3e..4a7958e 100644
--- a/chrome/browser/extensions/activity_log/activity_log_unittest.cc
+++ b/chrome/browser/extensions/activity_log/activity_log_unittest.cc
@@ -84,11 +84,15 @@
     scoped_refptr<Action> last = i->front();
     if (CommandLine::ForCurrentProcess()->HasSwitch(
         switches::kEnableExtensionActivityLogTesting))
-      args = "Injected scripts () onto "
-              "http://www.google.com/foo?bar extra";
+      args =
+          "ID=abc CATEGORY=content_script API=document.write ARGS=[\"\"] "
+          "PAGE_URL=http://www.google.com/foo?bar "
+          "OTHER={\"dom_verb\":3,\"extra\":\"extra\",\"page_title\":\"\"}";
     else
-      args = "Injected scripts () onto "
-              "http://www.google.com/foo extra";
+      args =
+          "ID=abc CATEGORY=content_script API=document.write ARGS=[\"\"] "
+          "PAGE_URL=http://www.google.com/foo "
+          "OTHER={\"dom_verb\":3,\"extra\":\"extra\",\"page_title\":\"\"}";
     ASSERT_EQ(args, last->PrintForDebug());
   }
 
@@ -96,8 +100,8 @@
       scoped_ptr<std::vector<scoped_refptr<Action> > > i) {
     scoped_refptr<Action> last = i->front();
     std::string id(kExtensionId);
-    std::string noargs = "ID: " + id + ", CATEGORY: "
-        "call, API: tabs.testMethod, ARGS: ";
+    std::string noargs =
+        "ID=" + id + " CATEGORY=api_call API=tabs.testMethod ARGS=[] OTHER={}";
     ASSERT_EQ(noargs, last->PrintForDebug());
   }
 
@@ -105,8 +109,9 @@
       scoped_ptr<std::vector<scoped_refptr<Action> > > i) {
     scoped_refptr<Action> last = i->front();
     std::string id(kExtensionId);
-    std::string args = "ID: " + id + ", CATEGORY: "
-        "call, API: extension.connect, ARGS: \"hello\", \"world\"";
+    std::string args = "ID=" + id +
+                       " CATEGORY=api_call API=extension.connect "
+                       "ARGS=[\"hello\",\"world\"] OTHER={}";
     ASSERT_EQ(args, last->PrintForDebug());
   }
 
@@ -122,8 +127,10 @@
       scoped_ptr<std::vector<scoped_refptr<Action> > > i) {
     ASSERT_EQ(1U, i->size());
     scoped_refptr<Action> last = i->front();
-    std::string args = "Injected scripts (\"script \") "
-        "onto http://www.google.com/ (prerender)";
+    std::string args =
+        "ID=odlameecjipmbmbejkplpemijjgpljce CATEGORY=content_script API= "
+        "ARGS=[\"\\\"script \\\"\"] PAGE_URL=http://www.google.com/ "
+        "OTHER={\"dom_verb\":3,\"extra\":\"(prerender)\",\"page_title\":\"\"}";
     ASSERT_EQ(args, last->PrintForDebug());
   }
 
@@ -242,7 +249,7 @@
   scoped_ptr<prerender::PrerenderHandle> prerender_handle(
       prerender_manager->AddPrerenderFromLocalPredictor(
           url,
-          web_contents()->GetController().GetSessionStorageNamespace(),
+          web_contents()->GetController().GetDefaultSessionStorageNamespace(),
           kSize));
 
   const std::vector<content::WebContents*> contentses =
@@ -264,3 +271,4 @@
 }
 
 }  // namespace extensions
+
diff --git a/chrome/browser/extensions/activity_log/api_actions.cc b/chrome/browser/extensions/activity_log/api_actions.cc
index 39ec099..bb50674 100644
--- a/chrome/browser/extensions/activity_log/api_actions.cc
+++ b/chrome/browser/extensions/activity_log/api_actions.cc
@@ -2,12 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/json/json_string_value_serializer.h"
 #include "base/logging.h"
 #include "base/memory/singleton.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
 #include "chrome/browser/extensions/activity_log/api_actions.h"
 #include "chrome/browser/extensions/activity_log/api_name_constants.h"
+#include "chrome/browser/extensions/activity_log/fullstream_ui_policy.h"
 #include "chrome/browser/extensions/extension_tab_util.h"
 #include "chrome/browser/ui/browser.h"
 #include "content/public/browser/browser_thread.h"
@@ -100,6 +102,13 @@
   std::map<std::string, std::string> nums_to_names_;  // <number label, name>
 };
 
+std::string Serialize(const base::Value& value) {
+  std::string value_as_text;
+  JSONStringValueSerializer serializer(&value_as_text);
+  serializer.SerializeAndOmitBinaryValues(value);
+  return value_as_text;
+}
+
 }  // namespace
 
 namespace extensions {
@@ -109,12 +118,6 @@
 using api::activity_log_private::ChromeActivityDetail;
 using api::activity_log_private::BlockedChromeActivityDetail;
 
-const char* APIAction::kTableName = "activitylog_apis";
-const char* APIAction::kTableContentFields[] =
-    {"api_type", "api_call", "args", "extra"};
-const char* APIAction::kTableFieldTypes[] =
-    {"INTEGER", "LONGVARCHAR", "LONGVARCHAR", "LONGVARCHAR"};
-
 // We should log the arguments to these API calls, even if argument logging is
 // disabled by default.
 const char* APIAction::kAlwaysLog[] =
@@ -133,22 +136,15 @@
                      const Type type,
                      const std::string& api_call,
                      const std::string& args,
+                     const base::ListValue& args_list,
                      const std::string& extra)
     : Action(extension_id, time, ExtensionActivity::ACTIVITY_TYPE_CHROME),
       type_(type),
       api_call_(api_call),
       args_(args),
+      args_list_(args_list.DeepCopy()),
       extra_(extra) { }
 
-APIAction::APIAction(const sql::Statement& s)
-    : Action(s.ColumnString(0),
-             base::Time::FromInternalValue(s.ColumnInt64(1)),
-             ExtensionActivity::ACTIVITY_TYPE_CHROME),
-      type_(static_cast<Type>(s.ColumnInt(2))),
-      api_call_(APINameMap::GetInstance()->ShortnameToApi(s.ColumnString(3))),
-      args_(s.ColumnString(4)),
-      extra_(s.ColumnString(5)) { }
-
 APIAction::~APIAction() {
 }
 
@@ -169,49 +165,28 @@
   return formatted_activity.Pass();
 }
 
-// static
-bool APIAction::InitializeTable(sql::Connection* db) {
-  // The original table schema was different than the existing one.
-  // We no longer want the api_action_type or target_type columns.
-  // Sqlite doesn't let you delete or modify existing columns, so we drop it.
-  // Any data loss incurred here doesn't matter since these fields existed
-  // before we started using the AL for anything.
-  if (db->DoesColumnExist(kTableName, "api_action_type")) {
-    std::string drop_table = base::StringPrintf("DROP TABLE %s", kTableName);
-    if (!db->Execute(drop_table.c_str()))
-      return false;
-  }
-  // We also now use INTEGER instead of VARCHAR for api_type.
-  if (db->DoesColumnExist(kTableName, "api_type")) {
-    std::string select = base::StringPrintf(
-        "SELECT api_type FROM %s ORDER BY rowid LIMIT 1", kTableName);
-    sql::Statement statement(db->GetUniqueStatement(select.c_str()));
-    if (statement.DeclaredColumnType(0) != sql::COLUMN_TYPE_INTEGER) {
-      std::string drop_table = base::StringPrintf("DROP TABLE %s", kTableName);
-      if (!db->Execute(drop_table.c_str()))
-        return false;
-    }
-  }
-  // Now initialize the table.
-  return InitializeTableInternal(db,
-                                 kTableName,
-                                 kTableContentFields,
-                                 kTableFieldTypes,
-                                 arraysize(kTableContentFields));
-}
-
 bool APIAction::Record(sql::Connection* db) {
-  std::string sql_str = "INSERT INTO " + std::string(kTableName)
-      + " (extension_id, time, api_type, api_call, args, extra) VALUES"
-      " (?,?,?,?,?,?)";
+  std::string sql_str =
+      "INSERT INTO " + std::string(FullStreamUIPolicy::kTableName) +
+      " (extension_id, time, action_type, api_name, args) VALUES"
+      " (?,?,?,?,?)";
   sql::Statement statement(db->GetCachedStatement(
       sql::StatementID(SQL_FROM_HERE), sql_str.c_str()));
   statement.BindString(0, extension_id());
   statement.BindInt64(1, time().ToInternalValue());
-  statement.BindInt(2, static_cast<int>(type_));
-  statement.BindString(3, APINameMap::GetInstance()->ApiToShortname(api_call_));
-  statement.BindString(4, args_);
-  statement.BindString(5, extra_);
+  switch (type_) {
+    case CALL:
+      statement.BindInt(2, static_cast<int>(Action::ACTION_API_CALL));
+      break;
+    case EVENT_CALLBACK:
+      statement.BindInt(2, static_cast<int>(Action::ACTION_API_EVENT));
+      break;
+    default:
+      LOG(ERROR) << "Invalid action type: " << type_;
+      return false;
+  }
+  statement.BindString(3, api_call_);
+  statement.BindString(4, Serialize(*args_list_));
   if (!statement.Run()) {
     LOG(ERROR) << "Activity log database I/O failed: " << sql_str;
     statement.Clear();
diff --git a/chrome/browser/extensions/activity_log/api_actions.h b/chrome/browser/extensions/activity_log/api_actions.h
index 4cd3cb0..9ea84ba 100644
--- a/chrome/browser/extensions/activity_log/api_actions.h
+++ b/chrome/browser/extensions/activity_log/api_actions.h
@@ -22,18 +22,11 @@
     UNKNOWN_TYPE = 2,
   };
 
-  static const char* kTableName;
-  static const char* kTableContentFields[];
-  static const char* kTableFieldTypes[];
   static const char* kAlwaysLog[];
   static const int kSizeAlwaysLog;
 
   static const char* kIncognitoUrl;
 
-  // Create the database table for storing APIActions, or update the schema if
-  // it is out of date.  Any existing data is preserved.
-  static bool InitializeTable(sql::Connection* db);
-
   // Create a new APIAction to describe a successful API call.  All
   // parameters are required.
   APIAction(const std::string& extension_id,
@@ -41,11 +34,9 @@
             const Type type,              // e.g. "CALL"
             const std::string& api_call,  // full method name
             const std::string& args,      // the argument list
+            const base::ListValue& args_list,  // same as above, as a list
             const std::string& extra);    // any extra logging info
 
-  // Create a new APIAction from a database row.
-  explicit APIAction(const sql::Statement& s);
-
   // Record the action in the database.
   virtual bool Record(sql::Connection* db) OVERRIDE;
 
@@ -76,6 +67,7 @@
   Type type_;
   std::string api_call_;
   std::string args_;
+  scoped_ptr<base::ListValue> args_list_;
   std::string extra_;
 
   DISALLOW_COPY_AND_ASSIGN(APIAction);
diff --git a/chrome/browser/extensions/activity_log/api_name_constants.h b/chrome/browser/extensions/activity_log/api_name_constants.h
index c8e62d9..0fe950d 100644
--- a/chrome/browser/extensions/activity_log/api_name_constants.h
+++ b/chrome/browser/extensions/activity_log/api_name_constants.h
@@ -193,7 +193,10 @@
     "tabs.getSelected", "tabs.sendRequest",
     "systemInfo.cpu.get", "systemInfo.memory.get",
     "runtime.onRestartRequired",
-    "system.cpu.getInfo"
+    "system.cpu.getInfo",
+    "system.display.getInfo",
+    "system.display.onDisplayChanged",
+    "system.display.setDisplayProperties"
 };
 
 }  // namespace activity_log_api_name_constants
diff --git a/chrome/browser/extensions/activity_log/blocked_actions.cc b/chrome/browser/extensions/activity_log/blocked_actions.cc
index e8c7bda..3ac47a1 100644
--- a/chrome/browser/extensions/activity_log/blocked_actions.cc
+++ b/chrome/browser/extensions/activity_log/blocked_actions.cc
@@ -2,9 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/json/json_string_value_serializer.h"
 #include "base/logging.h"
 #include "base/strings/stringprintf.h"
 #include "chrome/browser/extensions/activity_log/blocked_actions.h"
+#include "chrome/browser/extensions/activity_log/fullstream_ui_policy.h"
 #include "content/public/browser/browser_thread.h"
 
 using content::BrowserThread;
@@ -16,12 +18,6 @@
 using api::activity_log_private::ChromeActivityDetail;
 using api::activity_log_private::BlockedChromeActivityDetail;
 
-const char* BlockedAction::kTableName = "activitylog_blocked";
-const char* BlockedAction::kTableContentFields[] =
-    {"api_call", "args", "reason", "extra"};
-const char* BlockedAction::kTableFieldTypes[] =
-    {"LONGVARCHAR", "LONGVARCHAR", "INTEGER", "LONGVARCHAR"};
-
 BlockedAction::BlockedAction(const std::string& extension_id,
                              const base::Time& time,
                              const std::string& api_call,
@@ -36,15 +32,6 @@
       reason_(reason),
       extra_(extra) { }
 
-BlockedAction::BlockedAction(const sql::Statement& s)
-    : Action(s.ColumnString(0),
-             base::Time::FromInternalValue(s.ColumnInt64(1)),
-             ExtensionActivity::ACTIVITY_TYPE_BLOCKED_CHROME),
-      api_call_(s.ColumnString(2)),
-      args_(s.ColumnString(3)),
-      reason_(static_cast<Reason>(s.ColumnInt(4))),
-      extra_(s.ColumnString(5)) { }
-
 BlockedAction::~BlockedAction() {
 }
 
@@ -65,55 +52,32 @@
   return formatted_activity.Pass();
 }
 
-// static
-bool BlockedAction::InitializeTable(sql::Connection* db) {
-  // The original table schema was different than the existing one.
-  // Sqlite doesn't let you delete or modify existing columns, so we drop it.
-  // The old version can be identified because it had a field named
-  // blocked_action. Any data loss incurred here doesn't matter since these
-  // fields existed before we started using the AL for anything.
-  if (db->DoesColumnExist(kTableName, "blocked_action")) {
-    std::string drop_table = base::StringPrintf("DROP TABLE %s", kTableName);
-    if (!db->Execute(drop_table.c_str()))
-      return false;
-  }
-  // We also now use INTEGER instead of VARCHAR for url_action_type.
-  if (db->DoesColumnExist(kTableName, "reason")) {
-    std::string select = base::StringPrintf(
-        "SELECT reason FROM %s ORDER BY rowid LIMIT 1", kTableName);
-    sql::Statement statement(db->GetUniqueStatement(select.c_str()));
-    if (statement.DeclaredColumnType(0) != sql::COLUMN_TYPE_INTEGER) {
-      std::string drop_table = base::StringPrintf("DROP TABLE %s", kTableName);
-      if (!db->Execute(drop_table.c_str()))
-        return false;
-    }
-  }
-  return InitializeTableInternal(db,
-                                 kTableName,
-                                 kTableContentFields,
-                                 kTableFieldTypes,
-                                 arraysize(kTableContentFields));
-}
-
 bool BlockedAction::Record(sql::Connection* db) {
-  std::string sql_str = "INSERT INTO " + std::string(kTableName)
-    + " (extension_id, time, api_call, args, reason, extra)"
-    "  VALUES (?,?,?,?,?,?)";
+  std::string sql_str =
+      "INSERT INTO " + std::string(FullStreamUIPolicy::kTableName) +
+      " (extension_id, time, action_type, api_name, args, other) VALUES"
+      " (?,?,?,?,?,?)";
   sql::Statement statement(db->GetCachedStatement(
       sql::StatementID(SQL_FROM_HERE), sql_str.c_str()));
   statement.BindString(0, extension_id());
   statement.BindInt64(1, time().ToInternalValue());
-  statement.BindString(2, api_call_);
-  statement.BindString(3, args_);
-  statement.BindInt(4, static_cast<int>(reason_));
-  statement.BindString(5, extra_);
+  statement.BindInt(2, static_cast<int>(Action::ACTION_API_BLOCKED));
+  statement.BindString(3, api_call_);
+  statement.BindString(4, args_);
+
+  DictionaryValue other;
+  other.SetInteger("reason", static_cast<int>(reason_));
+  std::string other_string;
+  JSONStringValueSerializer other_serializer(&other_string);
+  other_serializer.SerializeAndOmitBinaryValues(other);
+  statement.BindString(5, other_string);
+
   if (!statement.Run()) {
     LOG(ERROR) << "Activity log database I/O failed: " << sql_str;
     statement.Clear();
     return false;
-  } else {
-    return true;
   }
+  return true;
 }
 
 std::string BlockedAction::PrintForDebug() {
diff --git a/chrome/browser/extensions/activity_log/blocked_actions.h b/chrome/browser/extensions/activity_log/blocked_actions.h
index 6f8bafd..e6f4beb 100644
--- a/chrome/browser/extensions/activity_log/blocked_actions.h
+++ b/chrome/browser/extensions/activity_log/blocked_actions.h
@@ -21,14 +21,6 @@
       QUOTA_EXCEEDED = 2,
   };
 
-  static const char* kTableName;
-  static const char* kTableContentFields[];
-  static const char* kTableFieldTypes[];
-
-  // Create a new database table for storing BlockedActions, or update the
-  // schema if it is out of date. Any existing data is preserved.
-  static bool InitializeTable(sql::Connection* db);
-
   // You must supply the id, time, api_call, and reason.
   BlockedAction(const std::string& extension_id,
                 const base::Time& time,
@@ -37,9 +29,6 @@
                 const Reason reason,                  // the reason it's blocked
                 const std::string& extra);            // any extra logging info
 
-  // Create a new BlockedAction from a database row.
-  explicit BlockedAction(const sql::Statement& s);
-
   // Record the action in the database.
   virtual bool Record(sql::Connection* db) OVERRIDE;
 
diff --git a/chrome/browser/extensions/activity_log/dom_actions.cc b/chrome/browser/extensions/activity_log/dom_actions.cc
index c597d41..9158abb 100644
--- a/chrome/browser/extensions/activity_log/dom_actions.cc
+++ b/chrome/browser/extensions/activity_log/dom_actions.cc
@@ -3,10 +3,12 @@
 // found in the LICENSE file.
 
 #include "base/command_line.h"
+#include "base/json/json_string_value_serializer.h"
 #include "base/logging.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/extensions/activity_log/dom_actions.h"
+#include "chrome/browser/extensions/activity_log/fullstream_ui_policy.h"
 #include "chrome/browser/history/url_database.h"
 #include "chrome/common/chrome_switches.h"
 #include "content/public/browser/browser_thread.h"
@@ -20,14 +22,6 @@
 using api::activity_log_private::ChromeActivityDetail;
 using api::activity_log_private::BlockedChromeActivityDetail;
 
-const char* DOMAction::kTableName = "activitylog_urls";
-const char* DOMAction::kTableContentFields[] =
-    {"url_action_type", "url_tld", "url_path", "url_title", "api_call",
-     "args", "extra"};
-const char* DOMAction::kTableFieldTypes[] =
-    {"INTEGER", "LONGVARCHAR", "LONGVARCHAR", "LONGVARCHAR", "LONGVARCHAR",
-     "LONGVARCHAR", "LONGVARCHAR"};
-
 DOMAction::DOMAction(const std::string& extension_id,
                      const base::Time& time,
                      const DomActionType::Type verb,
@@ -44,17 +38,6 @@
       args_(args),
       extra_(extra) { }
 
-DOMAction::DOMAction(const sql::Statement& s)
-    : Action(s.ColumnString(0),
-             base::Time::FromInternalValue(s.ColumnInt64(1)),
-             ExtensionActivity::ACTIVITY_TYPE_DOM),
-      verb_(static_cast<DomActionType::Type>(s.ColumnInt(2))),
-      url_(GURL(s.ColumnString(3)+ s.ColumnString(4))),
-      url_title_(s.ColumnString16(5)),
-      api_call_(s.ColumnString(6)),
-      args_(s.ColumnString(7)),
-      extra_(s.ColumnString(8)) { }
-
 DOMAction::~DOMAction() {
 }
 
@@ -77,73 +60,55 @@
   return formatted_activity.Pass();
 }
 
-// static
-bool DOMAction::InitializeTable(sql::Connection* db) {
-  // The original table schema was different than the existing one.
-  // Sqlite doesn't let you delete or modify existing columns, so we drop it.
-  // The old version can be identified because it had a field named
-  // tech_message. Any data loss incurred here doesn't matter since these
-  // fields existed before we started using the AL for anything.
-  if (db->DoesColumnExist(kTableName, "tech_message")) {
-    std::string drop_table = base::StringPrintf("DROP TABLE %s", kTableName);
-    if (!db->Execute(drop_table.c_str()))
-      return false;
-  }
-  // The url field is now broken into two parts - url_tld and url_path.
-  // ulr_tld contains the scheme, host, and port of the url and
-  // url_path contains the path.
-  if (db->DoesColumnExist(kTableName, "url")) {
-    std::string drop_table = base::StringPrintf("DROP TABLE %s", kTableName);
-    if (!db->Execute(drop_table.c_str()))
-      return false;
-  }
-  // We also now use INTEGER instead of VARCHAR for url_action_type.
-  if (db->DoesColumnExist(kTableName, "url_action_type")) {
-    std::string select = base::StringPrintf(
-        "SELECT url_action_type FROM %s ORDER BY rowid LIMIT 1", kTableName);
-    sql::Statement statement(db->GetUniqueStatement(select.c_str()));
-    if (statement.DeclaredColumnType(0) != sql::COLUMN_TYPE_INTEGER) {
-      std::string drop_table = base::StringPrintf("DROP TABLE %s", kTableName);
-      if (!db->Execute(drop_table.c_str()))
-        return false;
-    }
-  }
-  // Now initialize the table.
-  bool initialized = InitializeTableInternal(db,
-                                             kTableName,
-                                             kTableContentFields,
-                                             kTableFieldTypes,
-                                             arraysize(kTableContentFields));
-  return initialized;
-}
-
 bool DOMAction::Record(sql::Connection* db) {
-  std::string sql_str = "INSERT INTO " + std::string(kTableName) +
-      " (extension_id, time, url_action_type, url_tld, url_path, url_title,"
-      "  api_call, args, extra) VALUES (?,?,?,?,?,?,?,?,?)";
+  std::string sql_str = "INSERT INTO " +
+                        std::string(FullStreamUIPolicy::kTableName) +
+                        " (extension_id, time, action_type, api_name, args, "
+                        "page_url, arg_url, other) VALUES (?,?,?,?,?,?,?,?)";
   sql::Statement statement(db->GetCachedStatement(
       sql::StatementID(SQL_FROM_HERE), sql_str.c_str()));
-  std::string url_tld;
-  std::string url_path;
   statement.BindString(0, extension_id());
   statement.BindInt64(1, time().ToInternalValue());
-  statement.BindInt(2, static_cast<int>(verb_));
-  url_tld = url_.GetOrigin().spec();
-  // delete the extra "/"
-  if ((url_tld.size() > 0) && (url_tld[url_tld.size()-1] == '/'))
-    url_tld.erase(url_tld.size()-1);
-  statement.BindString(3, url_tld);
-  // If running in activity testing mode, store the parameters as well.
-  if ((CommandLine::ForCurrentProcess()->HasSwitch(
-       switches::kEnableExtensionActivityLogTesting)) && (url_.has_query()))
-    url_path = url_.path()+"?"+url_.query();
+  if (verb_ == DomActionType::INSERTED)
+    statement.BindInt(2, static_cast<int>(Action::ACTION_CONTENT_SCRIPT));
   else
-    url_path = url_.path();
-  statement.BindString(4, url_path);
-  statement.BindString16(5, url_title_);
-  statement.BindString(6, api_call_);
-  statement.BindString(7, args_);
-  statement.BindString(8, extra_);
+    statement.BindInt(2, static_cast<int>(Action::ACTION_DOM_ACCESS));
+  statement.BindString(3, api_call_);
+
+  ListValue args_list;
+  args_list.AppendString(args_);
+  std::string args_as_text;
+  JSONStringValueSerializer serializer(&args_as_text);
+  serializer.SerializeAndOmitBinaryValues(args_list);
+  statement.BindString(4, args_as_text);
+
+  // If running in activity testing mode, store the URL parameters as well.
+  GURL database_url;
+  if ((CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kEnableExtensionActivityLogTesting))) {
+    database_url = url_;
+  } else {
+    url_canon::Replacements<char> sanitize;
+    sanitize.ClearQuery();
+    sanitize.ClearRef();
+    database_url = url_.ReplaceComponents(sanitize);
+  }
+  statement.BindString(5, database_url.spec());
+
+  if (verb_ == DomActionType::INSERTED)
+    statement.BindString(6, args_);
+  else
+    statement.BindNull(6);
+
+  DictionaryValue other;
+  other.SetString("extra", extra_);
+  other.SetString("page_title", url_title_);
+  other.SetInteger("dom_verb", static_cast<int>(verb_));
+  std::string other_string;
+  JSONStringValueSerializer other_serializer(&other_string);
+  other_serializer.SerializeAndOmitBinaryValues(other);
+  statement.BindString(7, other_string);
+
   if (!statement.Run()) {
     LOG(ERROR) << "Activity log database I/O failed: " << sql_str;
     statement.Clear();
diff --git a/chrome/browser/extensions/activity_log/dom_actions.h b/chrome/browser/extensions/activity_log/dom_actions.h
index 1eff74b..9129a39 100644
--- a/chrome/browser/extensions/activity_log/dom_actions.h
+++ b/chrome/browser/extensions/activity_log/dom_actions.h
@@ -16,14 +16,6 @@
 // content script insertions.
 class DOMAction : public Action {
  public:
-  static const char* kTableName;
-  static const char* kTableContentFields[];
-  static const char* kTableFieldTypes[];
-
-  // Create a new database table for storing DOMActions, or update the schema if
-  // it is out of date. Any existing data is preserved.
-  static bool InitializeTable(sql::Connection* db);
-
   // Create a new DOMAction to describe a new DOM API call.
   // If the DOMAction is on a background page, the url & url_title may be null.
   // If the DOMAction refers to a content script insertion, api_call may be null
@@ -38,9 +30,6 @@
             const std::string& args,            // the args
             const std::string& extra);          // any extra logging info
 
-  // Create a new DOMAction from a database row.
-  explicit DOMAction(const sql::Statement& s);
-
   virtual scoped_ptr<api::activity_log_private::ExtensionActivity>
       ConvertToExtensionActivity() OVERRIDE;
 
diff --git a/chrome/browser/extensions/activity_log/fullstream_ui_policy.cc b/chrome/browser/extensions/activity_log/fullstream_ui_policy.cc
index 554d201..a6f7b22 100644
--- a/chrome/browser/extensions/activity_log/fullstream_ui_policy.cc
+++ b/chrome/browser/extensions/activity_log/fullstream_ui_policy.cc
@@ -6,6 +6,7 @@
 #include "base/json/json_string_value_serializer.h"
 #include "base/logging.h"
 #include "base/strings/string16.h"
+#include "base/strings/stringprintf.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"
@@ -32,14 +33,25 @@
 const char kKeyURLTitle[] =       "fsuip.urltitle";
 const char kKeyDetailsString[] =  "fsuip.details";
 
+// Obsolete database tables: these should be dropped from the database if
+// found.
+const char* kObsoleteTables[] = {"activitylog_apis", "activitylog_blocked",
+                                 "activitylog_urls"};
+
 }  // namespace
 
 namespace extensions {
 
-// TODO(dbabic) This would be a fine error handler for all sql-based policies,
-// so it would make sense to introduce another class in the hierarchy,
-// SQLiteBasedPolicy as a super class of FullStreamUIPolicy and move this
-// error handler (as well as other SQLite-related functionality) there.
+const char* FullStreamUIPolicy::kTableName = "activitylog_full";
+const char* FullStreamUIPolicy::kTableContentFields[] = {
+  "extension_id", "time", "action_type", "api_name", "args", "page_url",
+  "arg_url", "other"
+};
+const char* FullStreamUIPolicy::kTableFieldTypes[] = {
+  "LONGVARCHAR NOT NULL", "INTEGER", "INTEGER", "LONGVARCHAR", "LONGVARCHAR",
+  "LONGVARCHAR", "LONGVARCHAR", "LONGVARCHAR"
+};
+const int FullStreamUIPolicy::kTableFieldCount = arraysize(kTableContentFields);
 
 FullStreamUIPolicy::FullStreamUIPolicy(Profile* profile)
     : ActivityLogPolicy(profile) {
@@ -50,14 +62,24 @@
 }
 
 bool FullStreamUIPolicy::OnDatabaseInit(sql::Connection* db) {
-  if (!DOMAction::InitializeTable(db))
-    return false;
-  if (!APIAction::InitializeTable(db))
-    return false;
-  if (!BlockedAction::InitializeTable(db))
-    return false;
+  // Drop old database tables.
+  for (size_t i = 0; i < arraysize(kObsoleteTables); i++) {
+    const char* table_name = kObsoleteTables[i];
+    if (db->DoesTableExist(table_name)) {
+      std::string drop_statement =
+          base::StringPrintf("DROP TABLE %s", table_name);
+      if (!db->Execute(drop_statement.c_str())) {
+        return false;
+      }
+    }
+  }
 
-  return true;
+  // Create the unified activity log entry table.
+  return ActivityDatabase::InitializeTable(db,
+                                           kTableName,
+                                           kTableContentFields,
+                                           kTableFieldTypes,
+                                           arraysize(kTableContentFields));
 }
 
 void FullStreamUIPolicy::OnDatabaseClose() {
@@ -101,7 +123,17 @@
   }
 }
 
-std::string FullStreamUIPolicy::ProcessArguments(
+scoped_ptr<base::ListValue> FullStreamUIPolicy::ProcessArguments(
+    ActionType action_type,
+    const std::string& name,
+    const base::ListValue* args) const {
+  if (args)
+    return make_scoped_ptr(args->DeepCopy());
+  else
+    return scoped_ptr<base::ListValue>();
+}
+
+std::string FullStreamUIPolicy::JoinArguments(
     ActionType action_type,
     const std::string& name,
     const base::ListValue* args) const {
@@ -136,9 +168,11 @@
     const std::string& extension_id,
     const std::string& name,
     const GURL& url_param,
-    const base::ListValue* args,
+    const base::ListValue* args_in,
     const DictionaryValue* details) {
-  std::string concatenated_args = ProcessArguments(action_type, name, args);
+  scoped_ptr<base::ListValue> args =
+      ProcessArguments(action_type, name, args_in);
+  std::string concatenated_args = JoinArguments(action_type, name, args.get());
   const Time now = Time::Now();
   scoped_refptr<Action> action;
   std::string extra;
@@ -154,6 +188,7 @@
           APIAction::CALL,
           name,
           concatenated_args,
+          *args,
           extra);
       break;
     }
@@ -164,6 +199,7 @@
           APIAction::EVENT_CALLBACK,
           name,
           concatenated_args,
+          *args,
           extra);
       break;
     }
diff --git a/chrome/browser/extensions/activity_log/fullstream_ui_policy.h b/chrome/browser/extensions/activity_log/fullstream_ui_policy.h
index 3b33963..f915ad5 100644
--- a/chrome/browser/extensions/activity_log/fullstream_ui_policy.h
+++ b/chrome/browser/extensions/activity_log/fullstream_ui_policy.h
@@ -45,6 +45,12 @@
 
   virtual void Close() OVERRIDE;
 
+  // Database table schema.
+  static const char* kTableName;
+  static const char* kTableContentFields[];
+  static const char* kTableFieldTypes[];
+  static const int kTableFieldCount;
+
  protected:
   // Only ever run by OnDatabaseClose() below; see the comments on the
   // ActivityDatabase class for an overall discussion of how cleanup works.
@@ -55,10 +61,16 @@
   virtual bool OnDatabaseInit(sql::Connection* db) OVERRIDE;
   virtual void OnDatabaseClose() OVERRIDE;
 
-  // Concatenates arguments
-  virtual std::string ProcessArguments(ActionType action_type,
-                                       const std::string& name,
-                                       const base::ListValue* args) const;
+  // Strips arguments if needed by policy.
+  virtual scoped_ptr<base::ListValue> ProcessArguments(
+      ActionType action_type,
+      const std::string& name,
+      const base::ListValue* args) const;
+
+  // Concatenates arguments.
+  virtual std::string JoinArguments(ActionType action_type,
+                                    const std::string& name,
+                                    const base::ListValue* args) const;
 
   virtual void ProcessWebRequestModifications(
       base::DictionaryValue& details,
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 0028eaa..af735b9 100644
--- a/chrome/browser/extensions/activity_log/fullstream_ui_policy_unittest.cc
+++ b/chrome/browser/extensions/activity_log/fullstream_ui_policy_unittest.cc
@@ -66,8 +66,9 @@
   static void Arguments_Present(
       scoped_ptr<std::vector<scoped_refptr<Action> > > i) {
     scoped_refptr<Action> last = i->front();
-    std::string args = "ID: odlameecjipmbmbejkplpemijjgpljce, CATEGORY: "
-      "call, API: extension.connect, ARGS: \"hello\", \"world\"";
+    std::string args =
+        "ID=odlameecjipmbmbejkplpemijjgpljce CATEGORY=api_call "
+        "API=extension.connect ARGS=[\"hello\",\"world\"] OTHER={}";
     ASSERT_EQ(args, last->PrintForDebug());
   }
 
diff --git a/chrome/browser/extensions/activity_log/stream_noargs_ui_policy.cc b/chrome/browser/extensions/activity_log/stream_noargs_ui_policy.cc
index c30d33d..180b802 100644
--- a/chrome/browser/extensions/activity_log/stream_noargs_ui_policy.cc
+++ b/chrome/browser/extensions/activity_log/stream_noargs_ui_policy.cc
@@ -16,15 +16,15 @@
 
 StreamWithoutArgsUIPolicy::~StreamWithoutArgsUIPolicy() {}
 
-std::string StreamWithoutArgsUIPolicy::ProcessArguments(
+scoped_ptr<base::ListValue> StreamWithoutArgsUIPolicy::ProcessArguments(
     ActionType action_type,
     const std::string& name,
     const base::ListValue* args) const {
   if (action_type == ACTION_DOM ||
       arg_whitelist_api_.find(name) != arg_whitelist_api_.end()) {
-    return FullStreamUIPolicy::ProcessArguments(action_type, name, args);
+    return FullStreamUIPolicy::ProcessArguments(action_type, name, args).Pass();
   } else {
-    return std::string();
+    return make_scoped_ptr(new ListValue());
   }
 }
 
diff --git a/chrome/browser/extensions/activity_log/stream_noargs_ui_policy.h b/chrome/browser/extensions/activity_log/stream_noargs_ui_policy.h
index f91ffd0..46064b9 100644
--- a/chrome/browser/extensions/activity_log/stream_noargs_ui_policy.h
+++ b/chrome/browser/extensions/activity_log/stream_noargs_ui_policy.h
@@ -19,10 +19,10 @@
   virtual ~StreamWithoutArgsUIPolicy();
 
  protected:
-  virtual std::string ProcessArguments(ActionType action_type,
-                                       const std::string& name,
-                                       const base::ListValue* args)
-                                       const OVERRIDE;
+  virtual scoped_ptr<base::ListValue> ProcessArguments(
+      ActionType action_type,
+      const std::string& name,
+      const base::ListValue* args) const OVERRIDE;
 
   virtual void ProcessWebRequestModifications(
       base::DictionaryValue& details,
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 a1c806d..1a5dd4a 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
@@ -66,8 +66,9 @@
   static void Arguments_Missing(
       scoped_ptr<std::vector<scoped_refptr<Action> > > i) {
     scoped_refptr<Action> last = i->front();
-    std::string noargs = "ID: odlameecjipmbmbejkplpemijjgpljce, CATEGORY: "
-      "call, API: tabs.testMethod, ARGS: ";
+    std::string noargs =
+        "ID=odlameecjipmbmbejkplpemijjgpljce CATEGORY=api_call "
+        "API=tabs.testMethod ARGS=[] OTHER={}";
     ASSERT_EQ(noargs, last->PrintForDebug());
   }
 
diff --git a/chrome/browser/extensions/api/activity_log_private/activity_log_private_api_unittest.cc b/chrome/browser/extensions/api/activity_log_private/activity_log_private_api_unittest.cc
index 6aef614..841f09d 100644
--- a/chrome/browser/extensions/api/activity_log_private/activity_log_private_api_unittest.cc
+++ b/chrome/browser/extensions/api/activity_log_private/activity_log_private_api_unittest.cc
@@ -58,6 +58,7 @@
                   APIAction::CALL,
                   kApiCall,
                   kArgs,
+                  base::ListValue(),
                   kExtra));
   scoped_ptr<ExtensionActivity> result =
       action->ConvertToExtensionActivity();
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 81f5975..5b7bd40 100644
--- a/chrome/browser/extensions/api/app_runtime/app_runtime_api.cc
+++ b/chrome/browser/extensions/api/app_runtime/app_runtime_api.cc
@@ -30,17 +30,10 @@
                                  Profile* profile) {
   extensions::ExtensionSystem* system =
       extensions::ExtensionSystem::Get(profile);
-  // Special case: normally, extensions add their own lazy event listeners.
-  // However, since the extension might have just been enabled, it hasn't had a
-  // 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 (but an app that doesn't listen for the onLaunched event doesn't
-  // make sense anyway).
-  system->event_router()->AddLazyEventListener(kOnLaunched, extension_id);
   scoped_ptr<Event> event(new Event(kOnLaunched, args.Pass()));
   event->restrict_to_profile = profile;
-  system->event_router()->DispatchEventToExtension(extension_id, event.Pass());
-  system->event_router()->RemoveLazyEventListener(kOnLaunched, extension_id);
+  system->event_router()->DispatchEventWithLazyListener(extension_id,
+                                                        event.Pass());
 }
 
 }  // anonymous namespace
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 67d0cf1..9d25e6c 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
@@ -49,6 +49,7 @@
 namespace GetSubtree = api::bookmark_manager_private::GetSubtree;
 namespace manager_keys = bookmark_manager_api_constants;
 namespace Paste = api::bookmark_manager_private::Paste;
+namespace RemoveTrees = api::bookmark_manager_private::RemoveTrees;
 namespace SortChildren = api::bookmark_manager_private::SortChildren;
 namespace StartDrag = api::bookmark_manager_private::StartDrag;
 
@@ -534,4 +535,22 @@
   return true;
 }
 
+bool BookmarkManagerPrivateRemoveTreesFunction::RunImpl() {
+  scoped_ptr<RemoveTrees::Params> params(RemoveTrees::Params::Create(*args_));
+  EXTENSION_FUNCTION_VALIDATE(params);
+
+  BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
+  int64 id;
+  for (size_t i = 0; i < params->id_list.size(); ++i) {
+    if (!base::StringToInt64(params->id_list[i], &id)) {
+      error_ = bookmark_api_constants::kInvalidIdError;
+      return false;
+    }
+    if (!bookmark_api_helpers::RemoveNode(model, id, true, &error_))
+      return false;
+  }
+
+  return true;
+}
+
 }  // namespace extensions
diff --git a/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api.h b/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api.h
index aef42e9..ec699cb 100644
--- a/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api.h
+++ b/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api.h
@@ -217,6 +217,19 @@
   virtual bool RunImpl() OVERRIDE;
 };
 
+class BookmarkManagerPrivateRemoveTreesFunction
+    : public extensions::BookmarksFunction {
+ public:
+  DECLARE_EXTENSION_FUNCTION("bookmarkManagerPrivate.removeTrees",
+                             BOOKMARKMANAGERPRIVATE_REMOVETREES)
+
+ protected:
+  virtual ~BookmarkManagerPrivateRemoveTreesFunction() {}
+
+  // ExtensionFunction:
+  virtual bool RunImpl() OVERRIDE;
+};
+
 }  // namespace extensions
 
 #endif  // CHROME_BROWSER_EXTENSIONS_API_BOOKMARK_MANAGER_PRIVATE_BOOKMARK_MANAGER_PRIVATE_API_H_
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 35223b8..56631dd 100644
--- a/chrome/browser/extensions/api/content_settings/content_settings_api.cc
+++ b/chrome/browser/extensions/api/content_settings/content_settings_api.cc
@@ -40,8 +40,6 @@
 
 namespace {
 
-const std::vector<webkit::WebPluginInfo>* g_testing_plugins_;
-
 bool RemoveContentType(base::ListValue* args,
                        ContentSettingsType* content_type) {
   std::string content_type_str;
@@ -260,23 +258,19 @@
     return true;
   }
 
-  if (!g_testing_plugins_) {
-    PluginService::GetInstance()->GetPlugins(
-        base::Bind(&ContentSettingsContentSettingGetResourceIdentifiersFunction::
-                   OnGotPlugins,
-                   this));
-  } else {
-    OnGotPlugins(*g_testing_plugins_);
-  }
+  PluginService::GetInstance()->GetPlugins(
+      base::Bind(&ContentSettingsContentSettingGetResourceIdentifiersFunction::
+                 OnGotPlugins,
+                 this));
   return true;
 }
 
 void ContentSettingsContentSettingGetResourceIdentifiersFunction::OnGotPlugins(
-    const std::vector<webkit::WebPluginInfo>& plugins) {
+    const std::vector<content::WebPluginInfo>& plugins) {
   PluginFinder* finder = PluginFinder::GetInstance();
   std::set<std::string> group_identifiers;
   base::ListValue* list = new base::ListValue();
-  for (std::vector<webkit::WebPluginInfo>::const_iterator it = plugins.begin();
+  for (std::vector<content::WebPluginInfo>::const_iterator it = plugins.begin();
        it != plugins.end(); ++it) {
     scoped_ptr<PluginMetadata> plugin_metadata(finder->GetPluginMetadata(*it));
     const std::string& group_identifier = plugin_metadata->identifier();
@@ -298,10 +292,4 @@
           true));
 }
 
-// static
-void ContentSettingsContentSettingGetResourceIdentifiersFunction::
-    SetPluginsForTesting(const std::vector<webkit::WebPluginInfo>* plugins) {
-  g_testing_plugins_ = plugins;
-}
-
 }  // namespace extensions
diff --git a/chrome/browser/extensions/api/content_settings/content_settings_api.h b/chrome/browser/extensions/api/content_settings/content_settings_api.h
index dbd8ac1..820849f 100644
--- a/chrome/browser/extensions/api/content_settings/content_settings_api.h
+++ b/chrome/browser/extensions/api/content_settings/content_settings_api.h
@@ -9,7 +9,7 @@
 
 class PluginFinder;
 
-namespace webkit {
+namespace content {
 struct WebPluginInfo;
 }
 
@@ -67,11 +67,7 @@
 
   // Callback method that gets executed when |plugins|
   // are asynchronously fetched.
-  void OnGotPlugins(const std::vector<webkit::WebPluginInfo>& plugins);
-
-  // Used to override the global plugin list in tests.
-  static void SetPluginsForTesting(
-      const std::vector<webkit::WebPluginInfo>* plugins);
+  void OnGotPlugins(const std::vector<content::WebPluginInfo>& plugins);
 };
 
 }  // namespace extensions
diff --git a/chrome/browser/extensions/api/content_settings/content_settings_apitest.cc b/chrome/browser/extensions/api/content_settings/content_settings_apitest.cc
index b142e36..8c3bbed 100644
--- a/chrome/browser/extensions/api/content_settings/content_settings_apitest.cc
+++ b/chrome/browser/extensions/api/content_settings/content_settings_apitest.cc
@@ -12,7 +12,8 @@
 #include "chrome/browser/ui/browser.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
-#include "webkit/plugins/npapi/mock_plugin_list.h"
+#include "content/public/browser/plugin_service.h"
+#include "content/public/common/webplugininfo.h"
 
 namespace extensions {
 
@@ -94,12 +95,18 @@
                 url, url, CONTENT_SETTINGS_TYPE_NOTIFICATIONS, std::string()));
 }
 
-// Flaky on the trybots. See http://crbug.com/96725.
-IN_PROC_BROWSER_TEST_F(ExtensionApiTest,
-                       DISABLED_ContentSettingsGetResourceIdentifiers) {
-  CommandLine::ForCurrentProcess()->AppendSwitch(
-      switches::kEnableExperimentalExtensionApis);
+class ContentSettingsGetResourceIdentifiersTest : public ExtensionApiTest {
+ public:
+  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
+    ExtensionApiTest::SetUpCommandLine(command_line);
+    command_line->AppendSwitch(switches::kDisablePluginsDiscovery);
+    command_line->AppendSwitch(switches::kEnableExperimentalExtensionApis);
+  }
+};
 
+// Flaky on the trybots. See http://crbug.com/96725.
+IN_PROC_BROWSER_TEST_F(ContentSettingsGetResourceIdentifiersTest,
+                       DISABLED_Test) {
   base::FilePath::CharType kFooPath[] =
       FILE_PATH_LITERAL("/plugins/foo.plugin");
   base::FilePath::CharType kBarPath[] =
@@ -107,29 +114,21 @@
   const char* kFooName = "Foo Plugin";
   const char* kBarName = "Bar Plugin";
 
-  webkit::npapi::MockPluginList plugin_list;
-  plugin_list.AddPluginToLoad(
-      webkit::WebPluginInfo(ASCIIToUTF16(kFooName),
-                            base::FilePath(kFooPath),
-                            ASCIIToUTF16("1.2.3"),
-                            ASCIIToUTF16("foo")));
-  plugin_list.AddPluginToLoad(
-      webkit::WebPluginInfo(ASCIIToUTF16(kBarName),
-                            base::FilePath(kBarPath),
-                            ASCIIToUTF16("2.3.4"),
-                            ASCIIToUTF16("bar")));
-
-  std::vector<webkit::WebPluginInfo> plugins;
-  plugin_list.GetPlugins(&plugins);
-
-  ContentSettingsContentSettingGetResourceIdentifiersFunction::
-      SetPluginsForTesting(&plugins);
+  content::PluginService::GetInstance()->RegisterInternalPlugin(
+      content::WebPluginInfo(ASCIIToUTF16(kFooName),
+                             base::FilePath(kFooPath),
+                             ASCIIToUTF16("1.2.3"),
+                             ASCIIToUTF16("foo")),
+      false);
+  content::PluginService::GetInstance()->RegisterInternalPlugin(
+    content::WebPluginInfo(ASCIIToUTF16(kBarName),
+                           base::FilePath(kBarPath),
+                           ASCIIToUTF16("2.3.4"),
+                           ASCIIToUTF16("bar")),
+      false);
 
   EXPECT_TRUE(RunExtensionTest("content_settings/getresourceidentifiers"))
       << message_;
-
-  ContentSettingsContentSettingGetResourceIdentifiersFunction::
-      SetPluginsForTesting(NULL);
 }
 
 }  // namespace extensions
diff --git a/chrome/browser/extensions/api/debugger/debugger_api.cc b/chrome/browser/extensions/api/debugger/debugger_api.cc
index bdf9722..b1d8962 100644
--- a/chrome/browser/extensions/api/debugger/debugger_api.cc
+++ b/chrome/browser/extensions/api/debugger/debugger_api.cc
@@ -68,7 +68,9 @@
 namespace OnEvent = extensions::api::debugger::OnEvent;
 namespace SendCommand = extensions::api::debugger::SendCommand;
 
+namespace {
 class ExtensionDevToolsInfoBarDelegate;
+}  // namespace
 
 
 // ExtensionDevToolsClientHost ------------------------------------------------
@@ -82,7 +84,7 @@
       const std::string& extension_id,
       const std::string& extension_name,
       const Debuggee& debuggee,
-      ExtensionDevToolsInfoBarDelegate* infobar_delegate);
+      ExtensionDevToolsInfoBarDelegate* infobar);
 
   virtual ~ExtensionDevToolsClientHost();
 
@@ -117,19 +119,37 @@
   typedef std::map<int, scoped_refptr<DebuggerSendCommandFunction> >
       PendingRequests;
   PendingRequests pending_requests_;
-  ExtensionDevToolsInfoBarDelegate* infobar_delegate_;
+  ExtensionDevToolsInfoBarDelegate* infobar_;
   OnDetach::Reason detach_reason_;
 
   DISALLOW_COPY_AND_ASSIGN(ExtensionDevToolsClientHost);
 };
 
+// The member function declarations come after the other class declarations, so
+// they can call members on them.
+
+
+namespace {
+
+// Helpers --------------------------------------------------------------------
+
+void CopyDebuggee(Debuggee* dst, const Debuggee& src) {
+  if (src.tab_id)
+    dst->tab_id.reset(new int(*src.tab_id));
+  if (src.extension_id)
+    dst->extension_id.reset(new std::string(*src.extension_id));
+  if (src.target_id)
+    dst->target_id.reset(new std::string(*src.target_id));
+}
+
 
 // ExtensionDevToolsInfoBarDelegate -------------------------------------------
 
 class ExtensionDevToolsInfoBarDelegate : public ConfirmInfoBarDelegate {
  public:
-  // Creates an extension dev tools delegate and adds it to |infobar_service|.
-  // Returns a pointer to the delegate if it was successfully added.
+  // Creates an extension dev tools infobar delegate and adds it to the
+  // InfoBarService associated with |rvh|.  Returns the delegate if it was
+  // successfully added.
   static ExtensionDevToolsInfoBarDelegate* Create(
       RenderViewHost* rvh,
       const std::string& client_name);
@@ -214,26 +234,11 @@
 }
 
 bool ExtensionDevToolsInfoBarDelegate::Cancel() {
-  if (client_host_)
-    client_host_->MarkAsDismissed();
+  InfoBarDismissed();
   return true;
 }
 
 
-namespace {
-
-// Helpers --------------------------------------------------------------------
-
-void CopyDebuggee(Debuggee* dst, const Debuggee& src) {
-  if (src.tab_id)
-    dst->tab_id.reset(new int(*src.tab_id));
-  if (src.extension_id)
-    dst->extension_id.reset(new std::string(*src.extension_id));
-  if (src.target_id)
-    dst->target_id.reset(new std::string(*src.target_id));
-}
-
-
 // AttachedClientHosts --------------------------------------------------------
 
 class AttachedClientHosts {
@@ -261,6 +266,7 @@
 
 AttachedClientHosts::~AttachedClientHosts() {
 }
+
 // static
 AttachedClientHosts* AttachedClientHosts::GetInstance() {
   return Singleton<AttachedClientHosts>::get();
@@ -299,12 +305,12 @@
     const std::string& extension_id,
     const std::string& extension_name,
     const Debuggee& debuggee,
-    ExtensionDevToolsInfoBarDelegate* infobar_delegate)
+    ExtensionDevToolsInfoBarDelegate* infobar)
     : profile_(profile),
       agent_host_(agent_host),
       extension_id_(extension_id),
       last_request_id_(0),
-      infobar_delegate_(infobar_delegate),
+      infobar_(infobar),
       detach_reason_(OnDetach::REASON_TARGET_CLOSED) {
   CopyDebuggee(&debuggee_, debuggee);
 
@@ -324,8 +330,8 @@
   DevToolsManager::GetInstance()->RegisterDevToolsClientHostFor(
       agent_host_.get(), this);
 
-  if (infobar_delegate_) {
-    infobar_delegate_->set_client_host(this);
+  if (infobar_) {
+    infobar_->set_client_host(this);
     registrar_.Add(
         this, chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED,
         content::Source<InfoBarService>(InfoBarService::FromWebContents(
@@ -339,12 +345,10 @@
   // Close() us.
   registrar_.RemoveAll();
 
-  if (infobar_delegate_) {
-    infobar_delegate_->set_client_host(NULL);
-    InfoBarService* infobar_service = InfoBarService::FromWebContents(
-        WebContents::FromRenderViewHost(agent_host_->GetRenderViewHost()));
-    if (infobar_service)
-      infobar_service->RemoveInfoBar(infobar_delegate_);
+  if (infobar_) {
+    infobar_->set_client_host(NULL);
+    InfoBarService::FromWebContents(WebContents::FromRenderViewHost(
+        agent_host_->GetRenderViewHost()))->RemoveInfoBar(infobar_);
   }
   AttachedClientHosts::GetInstance()->Remove(this);
 }
@@ -412,9 +416,8 @@
     Close();
   } else {
     DCHECK_EQ(chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED, type);
-    if (content::Details<InfoBarRemovedDetails>(details)->first ==
-        infobar_delegate_) {
-      infobar_delegate_ = NULL;
+    if (content::Details<InfoBarRemovedDetails>(details)->first == infobar_) {
+      infobar_ = NULL;
       SendDetachedEvent();
       Close();
     }
@@ -463,7 +466,7 @@
 // DebuggerFunction -----------------------------------------------------------
 
 DebuggerFunction::DebuggerFunction()
-    : client_host_(0) {
+    : client_host_(NULL) {
 }
 
 DebuggerFunction::~DebuggerFunction() {
diff --git a/chrome/browser/extensions/api/declarative_webrequest/webrequest_condition_attribute.h b/chrome/browser/extensions/api/declarative_webrequest/webrequest_condition_attribute.h
index c79d482..f4c8f75 100644
--- a/chrome/browser/extensions/api/declarative_webrequest/webrequest_condition_attribute.h
+++ b/chrome/browser/extensions/api/declarative_webrequest/webrequest_condition_attribute.h
@@ -13,7 +13,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "chrome/browser/extensions/api/declarative_webrequest/request_stage.h"
 #include "chrome/common/extensions/api/events.h"
-#include "webkit/glue/resource_type.h"
+#include "webkit/common/resource_type.h"
 
 namespace base {
 class Value;
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 6da6d0e..8d24989 100644
--- a/chrome/browser/extensions/api/developer_private/developer_private_api.cc
+++ b/chrome/browser/extensions/api/developer_private/developer_private_api.cc
@@ -35,7 +35,6 @@
 #include "chrome/browser/sync_file_system/drive_backend/drive_file_sync_service.h"
 #include "chrome/browser/ui/chrome_select_file_policy.h"
 #include "chrome/browser/ui/webui/extensions/extension_icon_source.h"
-#include "chrome/common/chrome_switches.h"
 #include "chrome/common/extensions/api/developer_private.h"
 #include "chrome/common/extensions/background_info.h"
 #include "chrome/common/extensions/incognito_handler.h"
@@ -54,6 +53,7 @@
 #include "extensions/browser/view_type_utils.h"
 #include "extensions/common/constants.h"
 #include "extensions/common/extension_resource.h"
+#include "extensions/common/switches.h"
 #include "grit/chromium_strings.h"
 #include "grit/generated_resources.h"
 #include "net/base/net_util.h"
diff --git a/chrome/browser/extensions/api/identity/identity_apitest.cc b/chrome/browser/extensions/api/identity/identity_apitest.cc
index bf5351f..b4ec91c 100644
--- a/chrome/browser/extensions/api/identity/identity_apitest.cc
+++ b/chrome/browser/extensions/api/identity/identity_apitest.cc
@@ -29,6 +29,10 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
 
+#if defined(OS_WIN) && defined(USE_ASH)
+#include "base/win/windows_version.h"
+#endif
+
 using testing::_;
 using testing::Return;
 using testing::ReturnRef;
@@ -468,6 +472,12 @@
 
 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
                        NonInteractiveSuccess) {
+#if defined(OS_WIN) && defined(USE_ASH)
+  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
+  if (base::win::GetVersion() >= base::win::VERSION_WIN8)
+    return;
+#endif
+
   scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
   scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
   func->set_extension(extension.get());
@@ -1171,6 +1181,12 @@
 
 IN_PROC_BROWSER_TEST_F(
     LaunchWebAuthFlowFunctionTest, InteractiveFirstNavigationSuccess) {
+#if defined(OS_WIN) && defined(USE_ASH)
+  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
+  if (base::win::GetVersion() >= base::win::VERSION_WIN8)
+    return;
+#endif
+
   scoped_refptr<IdentityLaunchWebAuthFlowFunction> function(
       new IdentityLaunchWebAuthFlowFunction());
   scoped_refptr<Extension> empty_extension(
diff --git a/chrome/browser/extensions/api/identity/web_auth_flow.cc b/chrome/browser/extensions/api/identity/web_auth_flow.cc
index a3b2126..7f3ba05 100644
--- a/chrome/browser/extensions/api/identity/web_auth_flow.cc
+++ b/chrome/browser/extensions/api/identity/web_auth_flow.cc
@@ -99,12 +99,8 @@
         base::FilePath(FILE_PATH_LITERAL("identity_scope_approval_dialog")));
   }
 
-  system->event_router()->AddLazyEventListener(
-      "identityPrivate.onWebFlowRequest", extension_misc::kIdentityApiUiAppId);
-  system->event_router()->DispatchEventToExtension(
+  system->event_router()->DispatchEventWithLazyListener(
       extension_misc::kIdentityApiUiAppId, event.Pass());
-  system->event_router()->RemoveLazyEventListener(
-      "identityPrivate.onWebFlowRequest", extension_misc::kIdentityApiUiAppId);
 }
 
 void WebAuthFlow::DetachDelegateAndDelete() {
diff --git a/chrome/browser/extensions/api/media_galleries_private/media_galleries_eject_apitest.cc b/chrome/browser/extensions/api/media_galleries_private/media_galleries_eject_apitest.cc
index 32055eb..ba8407e 100644
--- a/chrome/browser/extensions/api/media_galleries_private/media_galleries_eject_apitest.cc
+++ b/chrome/browser/extensions/api/media_galleries_private/media_galleries_eject_apitest.cc
@@ -53,7 +53,9 @@
 
 class MediaGalleriesPrivateEjectApiTest : public ExtensionApiTest {
  public:
-  MediaGalleriesPrivateEjectApiTest() : device_id_(GetDeviceId()) {}
+  MediaGalleriesPrivateEjectApiTest()
+      : device_id_(GetDeviceId()),
+        monitor_(NULL) {}
   virtual ~MediaGalleriesPrivateEjectApiTest() {}
 
  protected:
@@ -64,6 +66,11 @@
                                     kTestExtensionId);
   }
 
+  virtual void SetUpOnMainThread() OVERRIDE {
+    monitor_ = chrome::test::TestStorageMonitor::CreateForBrowserTests();
+    ExtensionApiTest::SetUpOnMainThread();
+  }
+
   content::RenderViewHost* GetHost() {
     const extensions::Extension* extension =
         LoadExtension(test_data_dir_.AppendASCII(kTestExtensionPath));
@@ -103,6 +110,8 @@
  protected:
   const std::string device_id_;
 
+  chrome::test::TestStorageMonitor* monitor_;
+
  private:
   DISALLOW_COPY_AND_ASSIGN(MediaGalleriesPrivateEjectApiTest);
 };
@@ -113,11 +122,6 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 IN_PROC_BROWSER_TEST_F(MediaGalleriesPrivateEjectApiTest, EjectTest) {
-  scoped_ptr<chrome::test::TestStorageMonitor> monitor(
-      chrome::test::TestStorageMonitor::CreateForBrowserTests());
-  monitor->Init();
-  monitor->MarkInitialized();
-
   content::RenderViewHost* host = GetHost();
   ExecuteCmdAndCheckReply(host, kAddAttachListenerCmd, kAddAttachListenerOk);
 
@@ -130,18 +134,13 @@
   EXPECT_TRUE(attach_finished_listener.WaitUntilSatisfied());
 
   ExecuteCmdAndCheckReply(host, kEjectTestCmd, kEjectListenerOk);
-  EXPECT_EQ(device_id_, monitor->ejected_device());
+  EXPECT_EQ(device_id_, monitor_->ejected_device());
 
   Detach();
 }
 
 IN_PROC_BROWSER_TEST_F(MediaGalleriesPrivateEjectApiTest, EjectBadDeviceTest) {
-  scoped_ptr<chrome::test::TestStorageMonitor> monitor(
-      chrome::test::TestStorageMonitor::CreateForBrowserTests());
-  monitor->Init();
-  monitor->MarkInitialized();
-
   ExecuteCmdAndCheckReply(GetHost(), kEjectFailTestCmd, kEjectFailListenerOk);
 
-  EXPECT_EQ("", monitor->ejected_device());
+  EXPECT_EQ("", monitor_->ejected_device());
 }
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 45737e5..df662f0 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
@@ -108,12 +108,8 @@
 };
 
 IN_PROC_BROWSER_TEST_F(MediaGalleriesPrivateApiTest, DeviceAttachDetachEvents) {
-  scoped_ptr<chrome::test::TestStorageMonitor> monitor(
-      chrome::test::TestStorageMonitor::CreateForBrowserTests());
-  monitor->Init();
-  monitor->MarkInitialized();
-
   // Setup.
+  chrome::test::TestStorageMonitor::SyncInitialize();
   const extensions::Extension* extension =
       LoadExtension(test_data_dir_.AppendASCII(kTestExtensionPath));
   ASSERT_TRUE(extension);
diff --git a/chrome/browser/extensions/api/page_launcher/page_launcher_api.cc b/chrome/browser/extensions/api/page_launcher/page_launcher_api.cc
deleted file mode 100644
index e0f8241..0000000
--- a/chrome/browser/extensions/api/page_launcher/page_launcher_api.cc
+++ /dev/null
@@ -1,39 +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/extensions/api/page_launcher/page_launcher_api.h"
-
-#include "base/lazy_instance.h"
-#include "base/memory/linked_ptr.h"
-#include "chrome/browser/extensions/event_router.h"
-#include "chrome/browser/extensions/extension_system.h"
-#include "chrome/common/extensions/api/page_launcher.h"
-#include "url/gurl.h"
-
-namespace extensions {
-
-// static
-void PageLauncherAPI::DispatchOnClickedEvent(
-    Profile* profile,
-    const std::string& extension_id,
-    const GURL& url,
-    const std::string& mimetype,
-    const std::string* page_title,
-    const std::string* selected_text) {
-  api::page_launcher::PageData data;
-  data.url = url.spec();
-  data.mimetype = mimetype;
-  if (page_title)
-    data.title.reset(new std::string(*page_title));
-  if (selected_text)
-    data.selection_text.reset(new std::string(*selected_text));
-
-  scoped_ptr<Event> event(
-      new Event("pageLauncher.onClicked",
-                api::page_launcher::OnClicked::Create(data)));
-  EventRouter* event_router = ExtensionSystem::Get(profile)->event_router();
-  event_router->DispatchEventToExtension(extension_id, event.Pass());
-}
-
-}  // namespace extensions
diff --git a/chrome/browser/extensions/api/page_launcher/page_launcher_api.h b/chrome/browser/extensions/api/page_launcher/page_launcher_api.h
deleted file mode 100644
index a5c7757..0000000
--- a/chrome/browser/extensions/api/page_launcher/page_launcher_api.h
+++ /dev/null
@@ -1,28 +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_EXTENSIONS_API_PAGE_LAUNCHER_PAGE_LAUNCHER_API_H_
-#define CHROME_BROWSER_EXTENSIONS_API_PAGE_LAUNCHER_PAGE_LAUNCHER_API_H_
-
-#include <string>
-
-class GURL;
-class Profile;
-
-namespace extensions {
-
-class PageLauncherAPI {
- public:
-  static void DispatchOnClickedEvent(Profile* profile,
-                                     const std::string& extension_id,
-                                     const GURL& url,
-                                     const std::string& mimetype,
-                                     const std::string* page_title,
-                                     const std::string* selected_text);
-};
-
-}  // namespace extensions
-
-
-#endif  // CHROME_BROWSER_EXTENSIONS_API_PAGE_LAUNCHER_PAGE_LAUNCHER_API_H_
diff --git a/chrome/browser/extensions/api/preference/chrome_direct_setting.cc b/chrome/browser/extensions/api/preference/chrome_direct_setting.cc
index 161ef9b..6d1bd76 100644
--- a/chrome/browser/extensions/api/preference/chrome_direct_setting.cc
+++ b/chrome/browser/extensions/api/preference/chrome_direct_setting.cc
@@ -5,39 +5,16 @@
 #include "chrome/browser/extensions/api/preference/chrome_direct_setting.h"
 
 #include "base/containers/hash_tables.h"
+#include "base/lazy_instance.h"
 #include "base/prefs/pref_service.h"
 #include "base/values.h"
+#include "chrome/browser/extensions/api/preference/chrome_direct_setting_api.h"
 #include "chrome/browser/extensions/api/preference/preference_api_constants.h"
 #include "chrome/browser/profiles/profile.h"
 
 namespace extensions {
 namespace chromedirectsetting {
 
-namespace {
-
-class PreferenceWhitelist {
- public:
-  PreferenceWhitelist() {
-    whitelist_.insert("googlegeolocationaccess.enabled");
-  }
-
-  ~PreferenceWhitelist() {}
-
-  bool IsPreferenceOnWhitelist(const std::string& pref_key){
-    return whitelist_.find(pref_key) != whitelist_.end();
-  }
-
- private:
-  base::hash_set<std::string> whitelist_;
-
-  DISALLOW_COPY_AND_ASSIGN(PreferenceWhitelist);
-};
-
-static base::LazyInstance<PreferenceWhitelist> preference_whitelist_ =
-    LAZY_INSTANCE_INITIALIZER;
-
-}  // namespace
-
 DirectSettingFunctionBase::DirectSettingFunctionBase() {}
 
 DirectSettingFunctionBase::~DirectSettingFunctionBase() {}
@@ -50,11 +27,6 @@
   return GetExtension()->location() == Manifest::COMPONENT;
 }
 
-bool DirectSettingFunctionBase::IsPreferenceOnWhitelist(
-    const std::string& pref_key) {
-  return preference_whitelist_.Get().IsPreferenceOnWhitelist(pref_key);
-}
-
 GetDirectSettingFunction::GetDirectSettingFunction() {}
 
 bool GetDirectSettingFunction::RunImpl() {
@@ -62,7 +34,8 @@
 
   std::string pref_key;
   EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &pref_key));
-  EXTENSION_FUNCTION_VALIDATE(IsPreferenceOnWhitelist(pref_key));
+  EXTENSION_FUNCTION_VALIDATE(
+    ChromeDirectSettingAPI::Get(profile())->IsPreferenceOnWhitelist(pref_key));
 
   const PrefService::Preference* preference =
       GetPrefService()->FindPreference(pref_key.c_str());
@@ -85,7 +58,8 @@
 
   std::string pref_key;
   EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &pref_key));
-  EXTENSION_FUNCTION_VALIDATE(IsPreferenceOnWhitelist(pref_key));
+  EXTENSION_FUNCTION_VALIDATE(
+    ChromeDirectSettingAPI::Get(profile())->IsPreferenceOnWhitelist(pref_key));
 
   DictionaryValue* details = NULL;
   EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &details));
@@ -115,7 +89,8 @@
 
   std::string pref_key;
   EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &pref_key));
-  EXTENSION_FUNCTION_VALIDATE(IsPreferenceOnWhitelist(pref_key));
+  EXTENSION_FUNCTION_VALIDATE(
+    ChromeDirectSettingAPI::Get(profile())->IsPreferenceOnWhitelist(pref_key));
   GetPrefService()->ClearPref(pref_key.c_str());
 
   return true;
diff --git a/chrome/browser/extensions/api/preference/chrome_direct_setting.h b/chrome/browser/extensions/api/preference/chrome_direct_setting.h
index 1a8164b..7e36344 100644
--- a/chrome/browser/extensions/api/preference/chrome_direct_setting.h
+++ b/chrome/browser/extensions/api/preference/chrome_direct_setting.h
@@ -25,9 +25,6 @@
   // Returns true if the caller is a component extension.
   bool IsCalledFromComponentExtension();
 
-  // Returns true if the preference is on the whitelist.
-  bool IsPreferenceOnWhitelist(const std::string& pref_key);
-
  private:
   DISALLOW_COPY_AND_ASSIGN(DirectSettingFunctionBase);
 };
diff --git a/chrome/browser/extensions/api/preference/chrome_direct_setting_api.cc b/chrome/browser/extensions/api/preference/chrome_direct_setting_api.cc
new file mode 100644
index 0000000..04b4307
--- /dev/null
+++ b/chrome/browser/extensions/api/preference/chrome_direct_setting_api.cc
@@ -0,0 +1,154 @@
+// Copyright 2013 The Chromium Authors. 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/preference/chrome_direct_setting_api.h"
+
+#include "base/bind.h"
+#include "base/containers/hash_tables.h"
+#include "base/lazy_instance.h"
+#include "base/prefs/pref_change_registrar.h"
+#include "base/prefs/pref_service.h"
+#include "base/strings/stringprintf.h"
+#include "chrome/browser/extensions/api/preference/preference_api_constants.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/profiles/profile.h"
+
+namespace extensions {
+namespace chromedirectsetting {
+
+const char kOnPrefChangeFormat[] =
+    "types.private.ChromeDirectSetting.%s.onChange";
+
+class PreferenceWhitelist {
+ public:
+  PreferenceWhitelist() {
+    whitelist_.insert("googlegeolocationaccess.enabled");
+  }
+
+  ~PreferenceWhitelist() {}
+
+  bool IsPreferenceOnWhitelist(const std::string& pref_key){
+    return whitelist_.find(pref_key) != whitelist_.end();
+  }
+
+  void RegisterEventListeners(
+      Profile* profile,
+      EventRouter::Observer* observer) {
+    for (base::hash_set<std::string>::iterator iter = whitelist_.begin();
+         iter != whitelist_.end();
+         iter++) {
+      std::string event_name = base::StringPrintf(
+          kOnPrefChangeFormat,
+          (*iter).c_str());
+      ExtensionSystem::Get(profile)->event_router()->RegisterObserver(
+          observer,
+          event_name);
+    }
+  }
+
+  void RegisterPropertyListeners(
+      Profile* profile,
+      PrefChangeRegistrar* registrar,
+      const base::Callback<void(const std::string&)>& callback) {
+    for (base::hash_set<std::string>::iterator iter = whitelist_.begin();
+         iter != whitelist_.end();
+         iter++) {
+      const char* pref_key = (*iter).c_str();
+      std::string event_name = base::StringPrintf(
+          kOnPrefChangeFormat,
+          pref_key);
+      registrar->Add(pref_key, callback);
+    }
+  }
+
+ private:
+  base::hash_set<std::string> whitelist_;
+
+  DISALLOW_COPY_AND_ASSIGN(PreferenceWhitelist);
+};
+
+base::LazyInstance<PreferenceWhitelist> preference_whitelist =
+    LAZY_INSTANCE_INITIALIZER;
+
+static base::LazyInstance<ProfileKeyedAPIFactory<ChromeDirectSettingAPI> >
+    g_factory = LAZY_INSTANCE_INITIALIZER;
+
+ChromeDirectSettingAPI::ChromeDirectSettingAPI(Profile* profile)
+    : profile_(profile) {
+  preference_whitelist.Get().RegisterEventListeners(profile, this);
+}
+
+ChromeDirectSettingAPI::~ChromeDirectSettingAPI() {}
+
+// BrowserContextKeyedService implementation.
+void ChromeDirectSettingAPI::Shutdown() {}
+
+// ProfileKeyedAPI implementation.
+ProfileKeyedAPIFactory<ChromeDirectSettingAPI>*
+    ChromeDirectSettingAPI::GetFactoryInstance() {
+  return &g_factory.Get();
+}
+
+// EventRouter::Observer implementation.
+void ChromeDirectSettingAPI::OnListenerAdded(const EventListenerInfo& details) {
+  ExtensionSystem::Get(profile_)->event_router()->UnregisterObserver(this);
+  registrar_.Init(profile_->GetPrefs());
+  preference_whitelist.Get().RegisterPropertyListeners(
+      profile_,
+      &registrar_,
+      base::Bind(&ChromeDirectSettingAPI::OnPrefChanged,
+                 base::Unretained(this),
+                 registrar_.prefs()));
+}
+
+bool ChromeDirectSettingAPI::IsPreferenceOnWhitelist(
+    const std::string& pref_key) {
+  return preference_whitelist.Get().IsPreferenceOnWhitelist(pref_key);
+}
+
+ChromeDirectSettingAPI* ChromeDirectSettingAPI::Get(Profile* profile) {
+  return
+      ProfileKeyedAPIFactory<ChromeDirectSettingAPI>::GetForProfile(profile);
+}
+
+// ProfileKeyedAPI implementation.
+const char* ChromeDirectSettingAPI::service_name() {
+  return "ChromeDirectSettingAPI";
+}
+
+void ChromeDirectSettingAPI::OnPrefChanged(
+    PrefService* pref_service, const std::string& pref_key) {
+  std::string event_name = base::StringPrintf(kOnPrefChangeFormat,
+                                              pref_key.c_str());
+  EventRouter* router = ExtensionSystem::Get(profile_)->event_router();
+  if (router && router->HasEventListener(event_name)) {
+    const PrefService::Preference* preference =
+        profile_->GetPrefs()->FindPreference(pref_key.c_str());
+    const base::Value* value = preference->GetValue();
+
+    scoped_ptr<DictionaryValue> result(new DictionaryValue);
+    result->Set(preference_api_constants::kValue, value->DeepCopy());
+    base::ListValue args;
+    args.Append(result.release());
+
+    ExtensionService* extension_service =
+        ExtensionSystem::Get(profile_)->extension_service();
+    const ExtensionSet* extensions = extension_service->extensions();
+    for (ExtensionSet::const_iterator it = extensions->begin();
+         it != extensions->end(); ++it) {
+      if ((*it)->location() == Manifest::COMPONENT) {
+        std::string extension_id = (*it)->id();
+        if (router->ExtensionHasEventListener(extension_id, event_name)) {
+          scoped_ptr<base::ListValue> args_copy(args.DeepCopy());
+          scoped_ptr<Event> event(new Event(event_name, args_copy.Pass()));
+          router->DispatchEventToExtension(extension_id, event.Pass());
+        }
+      }
+    }
+  }
+}
+
+}  // namespace chromedirectsetting
+}  // namespace extensions
+
diff --git a/chrome/browser/extensions/api/preference/chrome_direct_setting_api.h b/chrome/browser/extensions/api/preference/chrome_direct_setting_api.h
new file mode 100644
index 0000000..4d5e9ff
--- /dev/null
+++ b/chrome/browser/extensions/api/preference/chrome_direct_setting_api.h
@@ -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.
+
+#ifndef CHROME_BROWSER_EXTENSIONS_API_PREFERENCE_CHROME_DIRECT_SETTING_API_H__
+#define CHROME_BROWSER_EXTENSIONS_API_PREFERENCE_CHROME_DIRECT_SETTING_API_H__
+
+#include "base/prefs/pref_change_registrar.h"
+#include "chrome/browser/extensions/api/profile_keyed_api_factory.h"
+#include "chrome/browser/extensions/event_router.h"
+
+class Profile;
+
+namespace extensions {
+namespace chromedirectsetting {
+
+class ChromeDirectSettingAPI : public ProfileKeyedAPI,
+                               public EventRouter::Observer {
+ public:
+  explicit ChromeDirectSettingAPI(Profile* profile);
+
+  virtual ~ChromeDirectSettingAPI();
+
+  // BrowserContextKeyedService implementation.
+  virtual void Shutdown() OVERRIDE;
+
+  // ProfileKeyedAPI implementation.
+  static ProfileKeyedAPIFactory<ChromeDirectSettingAPI>* GetFactoryInstance();
+
+  // EventRouter::Observer implementation.
+  virtual void OnListenerAdded(const EventListenerInfo& details) OVERRIDE;
+
+  // Returns true if the preference is on the whitelist.
+  bool IsPreferenceOnWhitelist(const std::string& pref_key);
+
+  // Convenience method to get the ChromeDirectSettingAPI for a profile.
+  static ChromeDirectSettingAPI* Get(Profile* profile);
+
+ private:
+  friend class ProfileKeyedAPIFactory<ChromeDirectSettingAPI>;
+
+  // ProfileKeyedAPI implementation.
+  static const char* service_name();
+
+  void OnPrefChanged(PrefService* pref_service, const std::string& pref_key);
+
+  static const bool kServiceIsNULLWhileTesting = true;
+  static const bool kServiceRedirectedInIncognito = false;
+
+  PrefChangeRegistrar registrar_;
+  Profile* profile_;
+
+  DISALLOW_COPY_AND_ASSIGN(ChromeDirectSettingAPI);
+};
+
+}  // namespace chromedirectsetting
+}  // namespace extensions
+
+#endif  // CHROME_BROWSER_EXTENSIONS_API_PREFERENCE_CHROME_DIRECT_SETTING_API_H__
+
diff --git a/chrome/browser/extensions/api/preference/preference_apitest.cc b/chrome/browser/extensions/api/preference/preference_apitest.cc
index 7b0aab5..98be5cd 100644
--- a/chrome/browser/extensions/api/preference/preference_apitest.cc
+++ b/chrome/browser/extensions/api/preference/preference_apitest.cc
@@ -11,7 +11,6 @@
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/ui_test_utils.h"
-#include "webkit/plugins/npapi/mock_plugin_list.h"
 
 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, PreferenceApi) {
   PrefService* pref_service = browser()->profile()->GetPrefs();
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 6a38470..c766c21 100644
--- a/chrome/browser/extensions/api/push_messaging/push_messaging_apitest.cc
+++ b/chrome/browser/extensions/api/push_messaging/push_messaging_apitest.cc
@@ -81,7 +81,10 @@
   void EmitInvalidation(
       const invalidation::ObjectId& object_id,
       const std::string& payload) {
-    fake_invalidation_service_->EmitInvalidationForTest(object_id, payload);
+    fake_invalidation_service_->EmitInvalidationForTest(
+        object_id,
+        syncer::Invalidation::kUnknownVersion,
+        payload);
   }
 
   PushMessagingAPI* GetAPI() {
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 9db3b46..2b0fac4 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
@@ -121,7 +121,10 @@
         *it, syncer::AckHandle::InvalidAckHandle()));
   }
   handler_->OnIncomingInvalidation(
-      ObjectIdSetToInvalidationMap(ids, "payload"));
+      ObjectIdSetToInvalidationMap(
+          ids,
+          syncer::Invalidation::kUnknownVersion,
+          "payload"));
 }
 
 // Tests that malformed object IDs don't trigger spurious callbacks.
@@ -158,7 +161,10 @@
         *it, syncer::AckHandle::InvalidAckHandle()));
   }
   handler_->OnIncomingInvalidation(
-      ObjectIdSetToInvalidationMap(ids, "payload"));
+      ObjectIdSetToInvalidationMap(
+          ids,
+          syncer::Invalidation::kUnknownVersion,
+          "payload"));
 }
 
 }  // namespace extensions
diff --git a/chrome/browser/extensions/api/runtime/runtime_api.cc b/chrome/browser/extensions/api/runtime/runtime_api.cc
index 146410f..6143f15 100644
--- a/chrome/browser/extensions/api/runtime/runtime_api.cc
+++ b/chrome/browser/extensions/api/runtime/runtime_api.cc
@@ -142,11 +142,6 @@
   if (!system)
     return;
 
-  // Special case: normally, extensions add their own lazy event listeners.
-  // However, since the extension has just been installed, it hasn't had a
-  // 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 base::ListValue());
   base::DictionaryValue* info = new base::DictionaryValue();
   event_args->Append(info);
@@ -159,11 +154,9 @@
     info->SetString(kInstallReason, kInstallReasonInstall);
   }
   DCHECK(system->event_router());
-  system->event_router()->AddLazyEventListener(kOnInstalledEvent, extension_id);
   scoped_ptr<Event> event(new Event(kOnInstalledEvent, event_args.Pass()));
-  system->event_router()->DispatchEventToExtension(extension_id, event.Pass());
-  system->event_router()->RemoveLazyEventListener(kOnInstalledEvent,
-                                                  extension_id);
+  system->event_router()->DispatchEventWithLazyListener(extension_id,
+                                                        event.Pass());
 }
 
 // static
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 7b507b2..071d1d0 100644
--- a/chrome/browser/extensions/api/streams_private/streams_private_apitest.cc
+++ b/chrome/browser/extensions/api/streams_private/streams_private_apitest.cc
@@ -26,6 +26,10 @@
 #include "net/test/embedded_test_server/http_response.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
+#if defined(OS_WIN) && defined(USE_ASH)
+#include "base/win/windows_version.h"
+#endif
+
 using content::BrowserContext;
 using content::BrowserThread;
 using content::DownloadItem;
@@ -202,6 +206,12 @@
 // installed, white-listed extension invokes the extension's
 // onExecuteContentHandler event (and does not start a download).
 IN_PROC_BROWSER_TEST_F(StreamsPrivateApiTest, Navigate) {
+#if defined(OS_WIN) && defined(USE_ASH)
+  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
+  if (base::win::GetVersion() >= base::win::VERSION_WIN8)
+    return;
+#endif
+
   ASSERT_TRUE(LoadTestExtension()) << message_;
 
   ResultCatcher catcher;
diff --git a/chrome/browser/extensions/api/system_info_display/display_info_provider.cc b/chrome/browser/extensions/api/system_display/display_info_provider.cc
similarity index 78%
rename from chrome/browser/extensions/api/system_info_display/display_info_provider.cc
rename to chrome/browser/extensions/api/system_display/display_info_provider.cc
index 9534ed3..c97435e 100644
--- a/chrome/browser/extensions/api/system_info_display/display_info_provider.cc
+++ b/chrome/browser/extensions/api/system_display/display_info_provider.cc
@@ -1,8 +1,8 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/extensions/api/system_info_display/display_info_provider.h"
+#include "chrome/browser/extensions/api/system_display/display_info_provider.h"
 
 namespace extensions {
 
diff --git a/chrome/browser/extensions/api/system_info_display/display_info_provider.h b/chrome/browser/extensions/api/system_display/display_info_provider.h
similarity index 77%
rename from chrome/browser/extensions/api/system_info_display/display_info_provider.h
rename to chrome/browser/extensions/api/system_display/display_info_provider.h
index 63a7077..037b5f1 100644
--- a/chrome/browser/extensions/api/system_info_display/display_info_provider.h
+++ b/chrome/browser/extensions/api/system_display/display_info_provider.h
@@ -1,19 +1,19 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_EXTENSIONS_API_SYSTEM_INFO_DISPLAY_DISPLAY_INFO_PROVIDER_H_
-#define CHROME_BROWSER_EXTENSIONS_API_SYSTEM_INFO_DISPLAY_DISPLAY_INFO_PROVIDER_H_
+#ifndef CHROME_BROWSER_EXTENSIONS_API_SYSTEM_DISPLAY_DISPLAY_INFO_PROVIDER_H_
+#define CHROME_BROWSER_EXTENSIONS_API_SYSTEM_DISPLAY_DISPLAY_INFO_PROVIDER_H_
 
 #include <string>
 
 #include "chrome/browser/extensions/api/system_info/system_info_provider.h"
-#include "chrome/common/extensions/api/system_info_display.h"
+#include "chrome/common/extensions/api/system_display.h"
 
 namespace extensions {
 
 typedef std::vector<linked_ptr<
-    api::system_info_display::DisplayUnitInfo> > DisplayInfo;
+    api::system_display::DisplayUnitInfo> > DisplayInfo;
 
 class DisplayInfoProvider : public SystemInfoProvider<DisplayInfo> {
  public:
@@ -39,7 +39,7 @@
   // This functionality is exposed only on ChromeOS.
   virtual void SetInfo(
       const std::string& display_id,
-      const api::system_info_display::DisplayProperties& info,
+      const api::system_display::DisplayProperties& info,
       const SetInfoCallback& callback);
 
   const DisplayInfo& display_info() const;
@@ -59,4 +59,4 @@
 
 }  // namespace extensions
 
-#endif  // CHROME_BROWSER_EXTENSIONS_API_SYSTEM_INFO_DISPLAY_DISPLAY_INFO_PROVIDER_H_
+#endif  // CHROME_BROWSER_EXTENSIONS_API_SYSTEM_DISPLAY_DISPLAY_INFO_PROVIDER_H_
diff --git a/chrome/browser/extensions/api/system_info_display/display_info_provider_chromeos.cc b/chrome/browser/extensions/api/system_display/display_info_provider_chromeos.cc
similarity index 96%
rename from chrome/browser/extensions/api/system_info_display/display_info_provider_chromeos.cc
rename to chrome/browser/extensions/api/system_display/display_info_provider_chromeos.cc
index e680bc2..712bc52 100644
--- a/chrome/browser/extensions/api/system_info_display/display_info_provider_chromeos.cc
+++ b/chrome/browser/extensions/api/system_display/display_info_provider_chromeos.cc
@@ -1,8 +1,8 @@
-// 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 "chrome/browser/extensions/api/system_info_display/display_info_provider.h"
+#include "chrome/browser/extensions/api/system_display/display_info_provider.h"
 
 #include "ash/display/display_controller.h"
 #include "ash/display/display_manager.h"
@@ -18,10 +18,10 @@
 
 namespace extensions {
 
-using api::system_info_display::Bounds;
-using api::system_info_display::DisplayUnitInfo;
-using api::system_info_display::DisplayProperties;
-using api::system_info_display::Insets;
+using api::system_display::Bounds;
+using api::system_display::DisplayUnitInfo;
+using api::system_display::DisplayProperties;
+using api::system_display::Insets;
 
 namespace {
 
@@ -73,8 +73,8 @@
                        DisplayManager* display_manager,
                        int64 primary_display_id,
                        DisplayInfo* list) {
-  linked_ptr<extensions::api::system_info_display::DisplayUnitInfo> unit(
-      new extensions::api::system_info_display::DisplayUnitInfo());
+  linked_ptr<extensions::api::system_display::DisplayUnitInfo> unit(
+      new extensions::api::system_display::DisplayUnitInfo());
   const gfx::Rect& bounds = display.bounds();
   const gfx::Rect& work_area = display.work_area();
   const float dpi = display.device_scale_factor() * kDpi96;
@@ -437,7 +437,7 @@
 
   int64 primary_id = ash::Shell::GetScreen()->GetPrimaryDisplay().id();
   for (size_t i = 0; i < display_manager->GetNumDisplays(); ++i) {
-    AddInfoForDisplay(*display_manager->GetDisplayAt(i), display_manager,
+    AddInfoForDisplay(display_manager->GetDisplayAt(i), display_manager,
                       primary_id, &info_);
   }
 
diff --git a/chrome/browser/extensions/api/system_info_display/display_info_provider_chromeos_unittest.cc b/chrome/browser/extensions/api/system_display/display_info_provider_chromeos_unittest.cc
similarity index 73%
rename from chrome/browser/extensions/api/system_info_display/display_info_provider_chromeos_unittest.cc
rename to chrome/browser/extensions/api/system_display/display_info_provider_chromeos_unittest.cc
index d157a26..5960313 100644
--- a/chrome/browser/extensions/api/system_info_display/display_info_provider_chromeos_unittest.cc
+++ b/chrome/browser/extensions/api/system_display/display_info_provider_chromeos_unittest.cc
@@ -2,10 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/extensions/api/system_info_display/display_info_provider.h"
+#include "chrome/browser/extensions/api/system_display/display_info_provider.h"
 
 #include "ash/display/display_controller.h"
 #include "ash/display/display_manager.h"
+#include "ash/screen_ash.h"
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
 #include "ash/test/display_manager_test_api.h"
@@ -45,7 +46,7 @@
 
   void CallSetDisplayUnitInfo(
       const std::string& display_id,
-      const api::system_info_display::DisplayProperties& info,
+      const api::system_display::DisplayProperties& info,
       bool* success,
       std::string* error) {
     DisplayInfoProvider::GetProvider()->SetInfo(display_id, info,
@@ -68,14 +69,14 @@
   }
 
   std::string SystemInfoDisplayInsetsToString(
-      const api::system_info_display::Insets& insets) const {
+      const api::system_display::Insets& insets) const {
     // Order to match gfx::Insets::ToString().
     return base::StringPrintf("%d,%d,%d,%d",
         insets.top,  insets.left, insets.bottom, insets.right);
   }
 
   std::string SystemInfoDisplayBoundsToString(
-      const api::system_info_display::Bounds& bounds) const {
+      const api::system_display::Bounds& bounds) const {
     // Order to match gfx::Rect::ToString().
     return base::StringPrintf("%d,%d %dx%d",
         bounds.left,  bounds.top, bounds.width, bounds.height);
@@ -331,347 +332,347 @@
 TEST_F(DisplayInfoProviderChromeosTest, SetBoundsOriginLeftExact) {
   UpdateDisplay("1200x600,520x400");
 
-  const gfx::Display* secondary = GetDisplayController()->GetSecondaryDisplay();
-  api::system_info_display::DisplayProperties info;
+  const gfx::Display& secondary = ash::ScreenAsh::GetSecondaryDisplay();
+  api::system_display::DisplayProperties info;
   info.bounds_origin_x.reset(new int(-520));
   info.bounds_origin_y.reset(new int(50));
 
   bool success = false;
   std::string error;
-  CallSetDisplayUnitInfo(base::Int64ToString(secondary->id()), info,
+  CallSetDisplayUnitInfo(base::Int64ToString(secondary.id()), info,
       &success, &error);
 
   ASSERT_TRUE(success);
   ASSERT_TRUE(error.empty());
 
-  EXPECT_EQ("-520,50 520x400", secondary->bounds().ToString());
+  EXPECT_EQ("-520,50 520x400", secondary.bounds().ToString());
 }
 
 TEST_F(DisplayInfoProviderChromeosTest, SetBoundsOriginRightExact) {
   UpdateDisplay("1200x600,520x400");
 
-  const gfx::Display* secondary = GetDisplayController()->GetSecondaryDisplay();
-  api::system_info_display::DisplayProperties info;
+  const gfx::Display& secondary = ash::ScreenAsh::GetSecondaryDisplay();
+  api::system_display::DisplayProperties info;
   info.bounds_origin_x.reset(new int(1200));
   info.bounds_origin_y.reset(new int(100));
 
   bool success = false;
   std::string error;
-  CallSetDisplayUnitInfo(base::Int64ToString(secondary->id()), info,
+  CallSetDisplayUnitInfo(base::Int64ToString(secondary.id()), info,
       &success, &error);
 
   ASSERT_TRUE(success);
   ASSERT_TRUE(error.empty());
 
-  EXPECT_EQ("1200,100 520x400", secondary->bounds().ToString());
+  EXPECT_EQ("1200,100 520x400", secondary.bounds().ToString());
 }
 
 TEST_F(DisplayInfoProviderChromeosTest, SetBoundsOriginTopExact) {
   UpdateDisplay("1200x600,520x400");
 
-  const gfx::Display* secondary = GetDisplayController()->GetSecondaryDisplay();
-  api::system_info_display::DisplayProperties info;
+  const gfx::Display& secondary = ash::ScreenAsh::GetSecondaryDisplay();
+  api::system_display::DisplayProperties info;
   info.bounds_origin_x.reset(new int(1100));
   info.bounds_origin_y.reset(new int(-400));
 
   bool success = false;
   std::string error;
-  CallSetDisplayUnitInfo(base::Int64ToString(secondary->id()), info,
+  CallSetDisplayUnitInfo(base::Int64ToString(secondary.id()), info,
       &success, &error);
 
   ASSERT_TRUE(success);
   ASSERT_TRUE(error.empty());
 
-  EXPECT_EQ("1100,-400 520x400", secondary->bounds().ToString());
+  EXPECT_EQ("1100,-400 520x400", secondary.bounds().ToString());
 }
 
 TEST_F(DisplayInfoProviderChromeosTest, SetBoundsOriginBottomExact) {
   UpdateDisplay("1200x600,520x400");
 
-  const gfx::Display* secondary = GetDisplayController()->GetSecondaryDisplay();
-  api::system_info_display::DisplayProperties info;
+  const gfx::Display& secondary = ash::ScreenAsh::GetSecondaryDisplay();
+  api::system_display::DisplayProperties info;
   info.bounds_origin_x.reset(new int(-350));
   info.bounds_origin_y.reset(new int(600));
 
   bool success = false;
   std::string error;
-  CallSetDisplayUnitInfo(base::Int64ToString(secondary->id()), info,
+  CallSetDisplayUnitInfo(base::Int64ToString(secondary.id()), info,
       &success, &error);
 
   ASSERT_TRUE(success);
   ASSERT_TRUE(error.empty());
 
-  EXPECT_EQ("-350,600 520x400", secondary->bounds().ToString());
+  EXPECT_EQ("-350,600 520x400", secondary.bounds().ToString());
 }
 
 TEST_F(DisplayInfoProviderChromeosTest, SetBoundsOriginSameCenter) {
   UpdateDisplay("1200x600,520x400");
 
-  const gfx::Display* secondary = GetDisplayController()->GetSecondaryDisplay();
-  api::system_info_display::DisplayProperties info;
+  const gfx::Display& secondary = ash::ScreenAsh::GetSecondaryDisplay();
+  api::system_display::DisplayProperties info;
   info.bounds_origin_x.reset(new int(340));
   info.bounds_origin_y.reset(new int(100));
 
   bool success = false;
   std::string error;
-  CallSetDisplayUnitInfo(base::Int64ToString(secondary->id()), info,
+  CallSetDisplayUnitInfo(base::Int64ToString(secondary.id()), info,
       &success, &error);
 
   ASSERT_TRUE(success);
   ASSERT_TRUE(error.empty());
 
-  EXPECT_EQ("1200,100 520x400", secondary->bounds().ToString());
+  EXPECT_EQ("1200,100 520x400", secondary.bounds().ToString());
 }
 
 TEST_F(DisplayInfoProviderChromeosTest, SetBoundsOriginLeftOutside) {
   UpdateDisplay("1200x600,520x400");
 
-  const gfx::Display* secondary = GetDisplayController()->GetSecondaryDisplay();
-  api::system_info_display::DisplayProperties info;
+  const gfx::Display& secondary = ash::ScreenAsh::GetSecondaryDisplay();
+  api::system_display::DisplayProperties info;
   info.bounds_origin_x.reset(new int(-1040));
   info.bounds_origin_y.reset(new int(100));
 
   bool success = false;
   std::string error;
-  CallSetDisplayUnitInfo(base::Int64ToString(secondary->id()), info,
+  CallSetDisplayUnitInfo(base::Int64ToString(secondary.id()), info,
       &success, &error);
 
   ASSERT_TRUE(success);
   ASSERT_TRUE(error.empty());
 
-  EXPECT_EQ("-520,100 520x400", secondary->bounds().ToString());
+  EXPECT_EQ("-520,100 520x400", secondary.bounds().ToString());
 }
 
 TEST_F(DisplayInfoProviderChromeosTest, SetBoundsOriginTopOutside) {
   UpdateDisplay("1200x600,520x400");
 
-  const gfx::Display* secondary = GetDisplayController()->GetSecondaryDisplay();
-  api::system_info_display::DisplayProperties info;
+  const gfx::Display& secondary = ash::ScreenAsh::GetSecondaryDisplay();
+  api::system_display::DisplayProperties info;
   info.bounds_origin_x.reset(new int(-360));
   info.bounds_origin_y.reset(new int(-301));
 
   bool success = false;
   std::string error;
-  CallSetDisplayUnitInfo(base::Int64ToString(secondary->id()), info,
+  CallSetDisplayUnitInfo(base::Int64ToString(secondary.id()), info,
       &success, &error);
 
   ASSERT_TRUE(success);
   ASSERT_TRUE(error.empty());
 
-  EXPECT_EQ("-360,-400 520x400", secondary->bounds().ToString());
+  EXPECT_EQ("-360,-400 520x400", secondary.bounds().ToString());
 }
 
 TEST_F(DisplayInfoProviderChromeosTest,
        SetBoundsOriginLeftButSharesBottomSide) {
   UpdateDisplay("1200x600,1000x100");
 
-  const gfx::Display* secondary = GetDisplayController()->GetSecondaryDisplay();
-  api::system_info_display::DisplayProperties info;
+  const gfx::Display& secondary = ash::ScreenAsh::GetSecondaryDisplay();
+  api::system_display::DisplayProperties info;
   info.bounds_origin_x.reset(new int(-650));
   info.bounds_origin_y.reset(new int(700));
 
   bool success = false;
   std::string error;
-  CallSetDisplayUnitInfo(base::Int64ToString(secondary->id()), info,
+  CallSetDisplayUnitInfo(base::Int64ToString(secondary.id()), info,
       &success, &error);
 
   ASSERT_TRUE(success);
   ASSERT_TRUE(error.empty());
 
-  EXPECT_EQ("-650,600 1000x100", secondary->bounds().ToString());
+  EXPECT_EQ("-650,600 1000x100", secondary.bounds().ToString());
 }
 
 TEST_F(DisplayInfoProviderChromeosTest,
        SetBoundsOriginRightButSharesTopSide) {
   UpdateDisplay("1200x600,1000x100");
 
-  const gfx::Display* secondary = GetDisplayController()->GetSecondaryDisplay();
-  api::system_info_display::DisplayProperties info;
+  const gfx::Display& secondary = ash::ScreenAsh::GetSecondaryDisplay();
+  api::system_display::DisplayProperties info;
   info.bounds_origin_x.reset(new int(850));
   info.bounds_origin_y.reset(new int(-150));
 
   bool success = false;
   std::string error;
-  CallSetDisplayUnitInfo(base::Int64ToString(secondary->id()), info,
+  CallSetDisplayUnitInfo(base::Int64ToString(secondary.id()), info,
       &success, &error);
 
   ASSERT_TRUE(success);
   ASSERT_TRUE(error.empty());
 
-  EXPECT_EQ("850,-100 1000x100", secondary->bounds().ToString());
+  EXPECT_EQ("850,-100 1000x100", secondary.bounds().ToString());
 }
 
 TEST_F(DisplayInfoProviderChromeosTest,
        SetBoundsOriginTopButSharesLeftSide) {
   UpdateDisplay("1200x600,1000x100/l");
 
-  const gfx::Display* secondary = GetDisplayController()->GetSecondaryDisplay();
-  api::system_info_display::DisplayProperties info;
+  const gfx::Display& secondary = ash::ScreenAsh::GetSecondaryDisplay();
+  api::system_display::DisplayProperties info;
   info.bounds_origin_x.reset(new int(-150));
   info.bounds_origin_y.reset(new int(-650));
 
   bool success = false;
   std::string error;
-  CallSetDisplayUnitInfo(base::Int64ToString(secondary->id()), info,
+  CallSetDisplayUnitInfo(base::Int64ToString(secondary.id()), info,
       &success, &error);
 
   ASSERT_TRUE(success);
   ASSERT_TRUE(error.empty());
 
-  EXPECT_EQ("-100,-650 100x1000", secondary->bounds().ToString());
+  EXPECT_EQ("-100,-650 100x1000", secondary.bounds().ToString());
 }
 
 TEST_F(DisplayInfoProviderChromeosTest,
        SetBoundsOriginBottomButSharesRightSide) {
   UpdateDisplay("1200x600,1000x100/l");
 
-  const gfx::Display* secondary = GetDisplayController()->GetSecondaryDisplay();
-  api::system_info_display::DisplayProperties info;
+  const gfx::Display& secondary = ash::ScreenAsh::GetSecondaryDisplay();
+  api::system_display::DisplayProperties info;
   info.bounds_origin_x.reset(new int(1350));
   info.bounds_origin_y.reset(new int(450));
 
   bool success = false;
   std::string error;
-  CallSetDisplayUnitInfo(base::Int64ToString(secondary->id()), info,
+  CallSetDisplayUnitInfo(base::Int64ToString(secondary.id()), info,
       &success, &error);
 
   ASSERT_TRUE(success);
   ASSERT_TRUE(error.empty());
 
-  EXPECT_EQ("1200,450 100x1000", secondary->bounds().ToString());
+  EXPECT_EQ("1200,450 100x1000", secondary.bounds().ToString());
 }
 
 TEST_F(DisplayInfoProviderChromeosTest, SetBoundsOriginPrimaryHiDPI) {
   UpdateDisplay("1200x600*2,500x500");
 
-  const gfx::Display* secondary = GetDisplayController()->GetSecondaryDisplay();
-  api::system_info_display::DisplayProperties info;
+  const gfx::Display& secondary = ash::ScreenAsh::GetSecondaryDisplay();
+  api::system_display::DisplayProperties info;
   info.bounds_origin_x.reset(new int(250));
   info.bounds_origin_y.reset(new int(-100));
 
   bool success = false;
   std::string error;
-  CallSetDisplayUnitInfo(base::Int64ToString(secondary->id()), info,
+  CallSetDisplayUnitInfo(base::Int64ToString(secondary.id()), info,
       &success, &error);
 
   ASSERT_TRUE(success);
   ASSERT_TRUE(error.empty());
 
-  EXPECT_EQ("600,-100 500x500", secondary->bounds().ToString());
+  EXPECT_EQ("600,-100 500x500", secondary.bounds().ToString());
 }
 
 TEST_F(DisplayInfoProviderChromeosTest, SetBoundsOriginSecondaryHiDPI) {
   UpdateDisplay("1200x600,600x1000*2");
 
-  const gfx::Display* secondary = GetDisplayController()->GetSecondaryDisplay();
-  api::system_info_display::DisplayProperties info;
+  const gfx::Display& secondary = ash::ScreenAsh::GetSecondaryDisplay();
+  api::system_display::DisplayProperties info;
   info.bounds_origin_x.reset(new int(450));
   info.bounds_origin_y.reset(new int(-100));
 
   bool success = false;
   std::string error;
-  CallSetDisplayUnitInfo(base::Int64ToString(secondary->id()), info,
+  CallSetDisplayUnitInfo(base::Int64ToString(secondary.id()), info,
       &success, &error);
 
   ASSERT_TRUE(success);
   ASSERT_TRUE(error.empty());
 
-  EXPECT_EQ("450,-500 300x500", secondary->bounds().ToString());
+  EXPECT_EQ("450,-500 300x500", secondary.bounds().ToString());
 }
 
 TEST_F(DisplayInfoProviderChromeosTest, SetBoundsOriginOutOfBounds) {
   UpdateDisplay("1200x600,600x1000*2");
 
-  const gfx::Display* secondary = GetDisplayController()->GetSecondaryDisplay();
-  api::system_info_display::DisplayProperties info;
+  const gfx::Display& secondary = ash::ScreenAsh::GetSecondaryDisplay();
+  api::system_display::DisplayProperties info;
   info.bounds_origin_x.reset(new int(0x200001));
   info.bounds_origin_y.reset(new int(-100));
 
   bool success = false;
   std::string error;
-  CallSetDisplayUnitInfo(base::Int64ToString(secondary->id()), info,
+  CallSetDisplayUnitInfo(base::Int64ToString(secondary.id()), info,
       &success, &error);
 
   ASSERT_FALSE(success);
   ASSERT_EQ("Bounds origin x out of bounds.", error);
 
-  EXPECT_EQ("1200,0 300x500", secondary->bounds().ToString());
+  EXPECT_EQ("1200,0 300x500", secondary.bounds().ToString());
 }
 
 TEST_F(DisplayInfoProviderChromeosTest, SetBoundsOriginOutOfBoundsNegative) {
   UpdateDisplay("1200x600,600x1000*2");
 
-  const gfx::Display* secondary = GetDisplayController()->GetSecondaryDisplay();
-  api::system_info_display::DisplayProperties info;
+  const gfx::Display& secondary = ash::ScreenAsh::GetSecondaryDisplay();
+  api::system_display::DisplayProperties info;
   info.bounds_origin_x.reset(new int(300));
   info.bounds_origin_y.reset(new int(-0x200001));
 
   bool success = false;
   std::string error;
-  CallSetDisplayUnitInfo(base::Int64ToString(secondary->id()), info,
+  CallSetDisplayUnitInfo(base::Int64ToString(secondary.id()), info,
       &success, &error);
 
   ASSERT_FALSE(success);
   ASSERT_EQ("Bounds origin y out of bounds.", error);
 
-  EXPECT_EQ("1200,0 300x500", secondary->bounds().ToString());
+  EXPECT_EQ("1200,0 300x500", secondary.bounds().ToString());
 }
 
 TEST_F(DisplayInfoProviderChromeosTest, SetBoundsOriginMaxValues) {
   UpdateDisplay("1200x4600,600x1000*2");
 
-  const gfx::Display* secondary = GetDisplayController()->GetSecondaryDisplay();
-  api::system_info_display::DisplayProperties info;
+  const gfx::Display& secondary = ash::ScreenAsh::GetSecondaryDisplay();
+  api::system_display::DisplayProperties info;
   info.bounds_origin_x.reset(new int(200000));
   info.bounds_origin_y.reset(new int(10));
 
   bool success = false;
   std::string error;
-  CallSetDisplayUnitInfo(base::Int64ToString(secondary->id()), info,
+  CallSetDisplayUnitInfo(base::Int64ToString(secondary.id()), info,
       &success, &error);
 
   ASSERT_TRUE(success);
   EXPECT_TRUE(error.empty());
 
-  EXPECT_EQ("1200,10 300x500", secondary->bounds().ToString());
+  EXPECT_EQ("1200,10 300x500", secondary.bounds().ToString());
 }
 
 TEST_F(DisplayInfoProviderChromeosTest, SetBoundsOriginOnPrimary) {
   UpdateDisplay("1200x600,600x1000*2");
 
-  const gfx::Display* secondary = GetDisplayController()->GetSecondaryDisplay();
-  api::system_info_display::DisplayProperties info;
+  const gfx::Display& secondary = ash::ScreenAsh::GetSecondaryDisplay();
+  api::system_display::DisplayProperties info;
   info.bounds_origin_x.reset(new int(300));
   info.is_primary.reset(new bool(true));
 
   bool success = false;
   std::string error;
-  CallSetDisplayUnitInfo(base::Int64ToString(secondary->id()), info,
+  CallSetDisplayUnitInfo(base::Int64ToString(secondary.id()), info,
       &success, &error);
 
   ASSERT_FALSE(success);
   ASSERT_EQ("Bounds origin not allowed for the primary display.", error);
 
-  EXPECT_EQ("1200,0 300x500", secondary->bounds().ToString());
+  EXPECT_EQ("1200,0 300x500", secondary.bounds().ToString());
   // The operation failed because the primary property would be set before
   // setting bounds. The primary display shouldn't have been changed, though.
-  EXPECT_NE(ash::DisplayController::GetPrimaryDisplay().id(), secondary->id());
+  EXPECT_NE(ash::DisplayController::GetPrimaryDisplay().id(), secondary.id());
 }
 
 TEST_F(DisplayInfoProviderChromeosTest, SetBoundsOriginWithMirroring) {
   UpdateDisplay("1200x600,600x1000*2");
 
-  const gfx::Display* secondary = GetDisplayController()->GetSecondaryDisplay();
+  const gfx::Display& secondary = ash::ScreenAsh::GetSecondaryDisplay();
   const gfx::Display& primary = GetDisplayController()->GetPrimaryDisplay();
 
-  api::system_info_display::DisplayProperties info;
+  api::system_display::DisplayProperties info;
   info.bounds_origin_x.reset(new int(300));
   info.mirroring_source_id.reset(
       new std::string(base::Int64ToString(primary.id())));
 
   bool success = false;
   std::string error;
-  CallSetDisplayUnitInfo(base::Int64ToString(secondary->id()), info,
+  CallSetDisplayUnitInfo(base::Int64ToString(secondary.id()), info,
       &success, &error);
 
   ASSERT_FALSE(success);
@@ -682,66 +683,66 @@
 TEST_F(DisplayInfoProviderChromeosTest, SetRotation) {
   UpdateDisplay("1200x600,600x1000*2");
 
-  const gfx::Display* secondary = GetDisplayController()->GetSecondaryDisplay();
-  api::system_info_display::DisplayProperties info;
+  const gfx::Display& secondary = ash::ScreenAsh::GetSecondaryDisplay();
+  api::system_display::DisplayProperties info;
   info.rotation.reset(new int(90));
 
   bool success = false;
   std::string error;
-  CallSetDisplayUnitInfo(base::Int64ToString(secondary->id()), info,
+  CallSetDisplayUnitInfo(base::Int64ToString(secondary.id()), info,
       &success, &error);
 
   ASSERT_TRUE(success);
   EXPECT_TRUE(error.empty());
 
-  EXPECT_EQ("1200,0 500x300", secondary->bounds().ToString());
-  EXPECT_EQ(gfx::Display::ROTATE_90, secondary->rotation());
+  EXPECT_EQ("1200,0 500x300", secondary.bounds().ToString());
+  EXPECT_EQ(gfx::Display::ROTATE_90, secondary.rotation());
 
   info.rotation.reset(new int(270));
-  CallSetDisplayUnitInfo(base::Int64ToString(secondary->id()), info,
+  CallSetDisplayUnitInfo(base::Int64ToString(secondary.id()), info,
       &success, &error);
 
   ASSERT_TRUE(success);
   EXPECT_TRUE(error.empty());
 
-  EXPECT_EQ("1200,0 500x300", secondary->bounds().ToString());
-  EXPECT_EQ(gfx::Display::ROTATE_270, secondary->rotation());
+  EXPECT_EQ("1200,0 500x300", secondary.bounds().ToString());
+  EXPECT_EQ(gfx::Display::ROTATE_270, secondary.rotation());
 
   info.rotation.reset(new int(180));
   // Switch primary display.
   info.is_primary.reset(new bool(true));
-  CallSetDisplayUnitInfo(base::Int64ToString(secondary->id()), info,
+  CallSetDisplayUnitInfo(base::Int64ToString(secondary.id()), info,
       &success, &error);
 
   ASSERT_TRUE(success);
   EXPECT_TRUE(error.empty());
 
-  EXPECT_EQ("0,0 300x500", secondary->bounds().ToString());
-  EXPECT_EQ(gfx::Display::ROTATE_180, secondary->rotation());
-  EXPECT_EQ(ash::DisplayController::GetPrimaryDisplay().id(), secondary->id());
+  EXPECT_EQ("0,0 300x500", secondary.bounds().ToString());
+  EXPECT_EQ(gfx::Display::ROTATE_180, secondary.rotation());
+  EXPECT_EQ(ash::DisplayController::GetPrimaryDisplay().id(), secondary.id());
 
   info.rotation.reset(new int(0));
-  CallSetDisplayUnitInfo(base::Int64ToString(secondary->id()), info,
+  CallSetDisplayUnitInfo(base::Int64ToString(secondary.id()), info,
       &success, &error);
 
   ASSERT_TRUE(success);
   EXPECT_TRUE(error.empty());
 
-  EXPECT_EQ("0,0 300x500", secondary->bounds().ToString());
-  EXPECT_EQ(gfx::Display::ROTATE_0, secondary->rotation());
-  EXPECT_EQ(ash::DisplayController::GetPrimaryDisplay().id(), secondary->id());
+  EXPECT_EQ("0,0 300x500", secondary.bounds().ToString());
+  EXPECT_EQ(gfx::Display::ROTATE_0, secondary.rotation());
+  EXPECT_EQ(ash::DisplayController::GetPrimaryDisplay().id(), secondary.id());
 }
 
 TEST_F(DisplayInfoProviderChromeosTest, SetInvalidRotation) {
   UpdateDisplay("1200x600,600x1000*2");
 
-  const gfx::Display* secondary = GetDisplayController()->GetSecondaryDisplay();
-  api::system_info_display::DisplayProperties info;
+  const gfx::Display& secondary = ash::ScreenAsh::GetSecondaryDisplay();
+  api::system_display::DisplayProperties info;
   info.rotation.reset(new int(91));
 
   bool success = false;
   std::string error;
-  CallSetDisplayUnitInfo(base::Int64ToString(secondary->id()), info,
+  CallSetDisplayUnitInfo(base::Int64ToString(secondary.id()), info,
       &success, &error);
 
   ASSERT_FALSE(success);
@@ -751,72 +752,72 @@
 TEST_F(DisplayInfoProviderChromeosTest, SetNegativeOverscan) {
   UpdateDisplay("1200x600,600x1000*2");
 
-  const gfx::Display* secondary = GetDisplayController()->GetSecondaryDisplay();
-  api::system_info_display::DisplayProperties info;
-  info.overscan.reset(new api::system_info_display::Insets);
+  const gfx::Display& secondary = ash::ScreenAsh::GetSecondaryDisplay();
+  api::system_display::DisplayProperties info;
+  info.overscan.reset(new api::system_display::Insets);
   info.overscan->left= -10;
 
   bool success = false;
   std::string error;
-  CallSetDisplayUnitInfo(base::Int64ToString(secondary->id()), info,
+  CallSetDisplayUnitInfo(base::Int64ToString(secondary.id()), info,
       &success, &error);
 
   ASSERT_FALSE(success);
   EXPECT_EQ("Negative overscan not allowed.", error);
 
-  EXPECT_EQ("1200,0 300x500", secondary->bounds().ToString());
+  EXPECT_EQ("1200,0 300x500", secondary.bounds().ToString());
 
   info.overscan->left= 0;
   info.overscan->right = -200;
 
-  CallSetDisplayUnitInfo(base::Int64ToString(secondary->id()), info,
+  CallSetDisplayUnitInfo(base::Int64ToString(secondary.id()), info,
       &success, &error);
 
   ASSERT_FALSE(success);
   EXPECT_EQ("Negative overscan not allowed.", error);
 
-  EXPECT_EQ("1200,0 300x500", secondary->bounds().ToString());
+  EXPECT_EQ("1200,0 300x500", secondary.bounds().ToString());
 
   info.overscan->right= 0;
   info.overscan->top = -300;
 
-  CallSetDisplayUnitInfo(base::Int64ToString(secondary->id()), info,
+  CallSetDisplayUnitInfo(base::Int64ToString(secondary.id()), info,
       &success, &error);
 
   ASSERT_FALSE(success);
   EXPECT_EQ("Negative overscan not allowed.", error);
 
-  EXPECT_EQ("1200,0 300x500", secondary->bounds().ToString());
+  EXPECT_EQ("1200,0 300x500", secondary.bounds().ToString());
 
   info.overscan->right= 0;
   info.overscan->top = -1000;
 
-  CallSetDisplayUnitInfo(base::Int64ToString(secondary->id()), info,
+  CallSetDisplayUnitInfo(base::Int64ToString(secondary.id()), info,
       &success, &error);
 
   ASSERT_FALSE(success);
   EXPECT_EQ("Negative overscan not allowed.", error);
 
-  EXPECT_EQ("1200,0 300x500", secondary->bounds().ToString());
+  EXPECT_EQ("1200,0 300x500", secondary.bounds().ToString());
 
   info.overscan->right= 0;
   info.overscan->top = 0;
 
-  CallSetDisplayUnitInfo(base::Int64ToString(secondary->id()), info,
+  CallSetDisplayUnitInfo(base::Int64ToString(secondary.id()), info,
       &success, &error);
 
   ASSERT_TRUE(success);
   EXPECT_TRUE(error.empty());
 
-  EXPECT_EQ("1200,0 300x500", secondary->bounds().ToString());
+  EXPECT_EQ("1200,0 300x500", secondary.bounds().ToString());
 }
 
 TEST_F(DisplayInfoProviderChromeosTest, SetOverscanLargerThanHorizontalBounds) {
   UpdateDisplay("1200x600,600x1000*2");
 
-  const gfx::Display* secondary = GetDisplayController()->GetSecondaryDisplay();
-  api::system_info_display::DisplayProperties info;
-  info.overscan.reset(new api::system_info_display::Insets);
+  const gfx::Display& secondary = ash::ScreenAsh::GetSecondaryDisplay();
+  api::system_display::DisplayProperties info;
+  info.overscan.reset(new api::system_display::Insets);
   // Horizontal overscan is 151, which would make the bounds width 149.
   info.overscan->left= 50;
   info.overscan->top = 10;
@@ -825,7 +826,7 @@
 
   bool success = false;
   std::string error;
-  CallSetDisplayUnitInfo(base::Int64ToString(secondary->id()), info,
+  CallSetDisplayUnitInfo(base::Int64ToString(secondary.id()), info,
       &success, &error);
 
   ASSERT_FALSE(success);
@@ -836,9 +837,9 @@
 TEST_F(DisplayInfoProviderChromeosTest, SetOverscanLargerThanVerticalBounds) {
   UpdateDisplay("1200x600,600x1000");
 
-  const gfx::Display* secondary = GetDisplayController()->GetSecondaryDisplay();
-  api::system_info_display::DisplayProperties info;
-  info.overscan.reset(new api::system_info_display::Insets);
+  const gfx::Display& secondary = ash::ScreenAsh::GetSecondaryDisplay();
+  api::system_display::DisplayProperties info;
+  info.overscan.reset(new api::system_display::Insets);
   // Vertical overscan is 501, which would make the bounds height 499.
   info.overscan->left= 20;
   info.overscan->top = 250;
@@ -847,7 +848,7 @@
 
   bool success = false;
   std::string error;
-  CallSetDisplayUnitInfo(base::Int64ToString(secondary->id()), info,
+  CallSetDisplayUnitInfo(base::Int64ToString(secondary.id()), info,
       &success, &error);
 
   ASSERT_FALSE(success);
@@ -858,9 +859,9 @@
 TEST_F(DisplayInfoProviderChromeosTest, SetOverscan) {
   UpdateDisplay("1200x600,600x1000*2");
 
-  const gfx::Display* secondary = GetDisplayController()->GetSecondaryDisplay();
-  api::system_info_display::DisplayProperties info;
-  info.overscan.reset(new api::system_info_display::Insets);
+  const gfx::Display& secondary = ash::ScreenAsh::GetSecondaryDisplay();
+  api::system_display::DisplayProperties info;
+  info.overscan.reset(new api::system_display::Insets);
   info.overscan->left= 20;
   info.overscan->top = 199;
   info.overscan->right = 130;
@@ -868,15 +869,15 @@
 
   bool success = false;
   std::string error;
-  CallSetDisplayUnitInfo(base::Int64ToString(secondary->id()), info,
+  CallSetDisplayUnitInfo(base::Int64ToString(secondary.id()), info,
       &success, &error);
 
   ASSERT_TRUE(success);
   EXPECT_TRUE(error.empty());
 
-  EXPECT_EQ("1200,0 150x250", secondary->bounds().ToString());
+  EXPECT_EQ("1200,0 150x250", secondary.bounds().ToString());
   const gfx::Insets overscan =
-      GetDisplayManager()->GetOverscanInsets(secondary->id());
+      GetDisplayManager()->GetOverscanInsets(secondary.id());
 
   EXPECT_EQ(20, overscan.left());
   EXPECT_EQ(199, overscan.top());
@@ -890,8 +891,8 @@
       ash::test::DisplayManagerTestApi(GetDisplayManager()).
       SetFirstDisplayAsInternalDisplay();
 
-  api::system_info_display::DisplayProperties info;
-  info.overscan.reset(new api::system_info_display::Insets);
+  api::system_display::DisplayProperties info;
+  info.overscan.reset(new api::system_display::Insets);
   // Vertical overscan is 501, which would make the bounds height 499.
   info.overscan->left= 20;
   info.overscan->top = 20;
diff --git a/chrome/browser/extensions/api/system_info_display/display_info_provider_mac.cc b/chrome/browser/extensions/api/system_display/display_info_provider_mac.cc
similarity index 75%
rename from chrome/browser/extensions/api/system_info_display/display_info_provider_mac.cc
rename to chrome/browser/extensions/api/system_display/display_info_provider_mac.cc
index 3ff9d6b..2b22e1e 100644
--- a/chrome/browser/extensions/api/system_info_display/display_info_provider_mac.cc
+++ b/chrome/browser/extensions/api/system_display/display_info_provider_mac.cc
@@ -1,8 +1,8 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/extensions/api/system_info_display/display_info_provider.h"
+#include "chrome/browser/extensions/api/system_display/display_info_provider.h"
 
 namespace extensions {
 
@@ -13,7 +13,7 @@
 
 void DisplayInfoProvider::SetInfo(
     const std::string& display_id,
-    const api::system_info_display::DisplayProperties& info,
+    const api::system_display::DisplayProperties& info,
     const SetInfoCallback& callback) {
   base::MessageLoopProxy::current()->PostTask(
       FROM_HERE,
diff --git a/chrome/browser/extensions/api/system_info_display/display_info_provider_win.cc b/chrome/browser/extensions/api/system_display/display_info_provider_win.cc
similarity index 89%
rename from chrome/browser/extensions/api/system_info_display/display_info_provider_win.cc
rename to chrome/browser/extensions/api/system_display/display_info_provider_win.cc
index e242fbb..9d21278 100644
--- a/chrome/browser/extensions/api/system_info_display/display_info_provider_win.cc
+++ b/chrome/browser/extensions/api/system_display/display_info_provider_win.cc
@@ -1,8 +1,8 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/extensions/api/system_info_display/display_info_provider.h"
+#include "chrome/browser/extensions/api/system_display/display_info_provider.h"
 
 #include <windows.h>
 
@@ -13,8 +13,8 @@
 
 namespace extensions {
 
-using api::system_info_display::Bounds;
-using api::system_info_display::DisplayUnitInfo;
+using api::system_display::Bounds;
+using api::system_display::DisplayUnitInfo;
 
 namespace {
 
@@ -74,7 +74,7 @@
 
 void DisplayInfoProvider::SetInfo(
     const std::string& display_id,
-    const api::system_info_display::DisplayProperties& info,
+    const api::system_display::DisplayProperties& info,
     const SetInfoCallback& callback) {
   base::MessageLoopProxy::current()->PostTask(
       FROM_HERE,
diff --git a/chrome/browser/extensions/api/system_info_display/display_info_provider_x11.cc b/chrome/browser/extensions/api/system_display/display_info_provider_x11.cc
similarity index 75%
rename from chrome/browser/extensions/api/system_info_display/display_info_provider_x11.cc
rename to chrome/browser/extensions/api/system_display/display_info_provider_x11.cc
index a3f46d0..adfdb14 100644
--- a/chrome/browser/extensions/api/system_info_display/display_info_provider_x11.cc
+++ b/chrome/browser/extensions/api/system_display/display_info_provider_x11.cc
@@ -1,8 +1,8 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/extensions/api/system_info_display/display_info_provider.h"
+#include "chrome/browser/extensions/api/system_display/display_info_provider.h"
 
 namespace extensions {
 
@@ -13,7 +13,7 @@
 
 void DisplayInfoProvider::SetInfo(
     const std::string& display_id,
-    const api::system_info_display::DisplayProperties& info,
+    const api::system_display::DisplayProperties& info,
     const SetInfoCallback& callback) {
   base::MessageLoopProxy::current()->PostTask(
       FROM_HERE,
diff --git a/chrome/browser/extensions/api/system_info_display/system_info_display_api.cc b/chrome/browser/extensions/api/system_display/system_display_api.cc
similarity index 60%
rename from chrome/browser/extensions/api/system_info_display/system_info_display_api.cc
rename to chrome/browser/extensions/api/system_display/system_display_api.cc
index d2c8748..8819a8c 100644
--- a/chrome/browser/extensions/api/system_info_display/system_info_display_api.cc
+++ b/chrome/browser/extensions/api/system_display/system_display_api.cc
@@ -1,30 +1,30 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/extensions/api/system_info_display/system_info_display_api.h"
+#include "chrome/browser/extensions/api/system_display/system_display_api.h"
 
 #include "base/memory/scoped_ptr.h"
 #include "chrome/common/extensions/manifest_handlers/kiosk_enabled_info.h"
 
 namespace extensions {
 
-using api::system_info_display::DisplayUnitInfo;
+using api::system_display::DisplayUnitInfo;
 
-namespace SetDisplayProperties = api::system_info_display::SetDisplayProperties;
+namespace SetDisplayProperties = api::system_display::SetDisplayProperties;
 
-bool SystemInfoDisplayGetDisplayInfoFunction::RunImpl() {
+bool SystemDisplayGetInfoFunction::RunImpl() {
   DisplayInfoProvider::GetProvider()->RequestInfo(
       base::Bind(
-          &SystemInfoDisplayGetDisplayInfoFunction::OnGetDisplayInfoCompleted,
+          &SystemDisplayGetInfoFunction::OnGetDisplayInfoCompleted,
           this));
   return true;
 }
 
-void SystemInfoDisplayGetDisplayInfoFunction::OnGetDisplayInfoCompleted(
+void SystemDisplayGetInfoFunction::OnGetDisplayInfoCompleted(
     bool success) {
   if (success) {
-    results_ = api::system_info_display::GetDisplayInfo::Results::Create(
+    results_ = api::system_display::GetInfo::Results::Create(
                    DisplayInfoProvider::GetProvider()->display_info());
   } else {
     SetError("Error occurred when querying display information.");
@@ -32,7 +32,7 @@
   SendResponse(success);
 }
 
-bool SystemInfoDisplaySetDisplayPropertiesFunction::RunImpl() {
+bool SystemDisplaySetDisplayPropertiesFunction::RunImpl() {
 #if !defined(OS_CHROMEOS)
   SetError("Function available only on ChromeOS.");
   return false;
@@ -46,13 +46,13 @@
       SetDisplayProperties::Params::Create(*args_));
   DisplayInfoProvider::GetProvider()->SetInfo(params->id, params->info,
       base::Bind(
-          &SystemInfoDisplaySetDisplayPropertiesFunction::OnPropertiesSet,
+          &SystemDisplaySetDisplayPropertiesFunction::OnPropertiesSet,
           this));
   return true;
 #endif
 }
 
-void SystemInfoDisplaySetDisplayPropertiesFunction::OnPropertiesSet(
+void SystemDisplaySetDisplayPropertiesFunction::OnPropertiesSet(
     bool success, const std::string& error) {
   if (!success)
     SetError(error);
diff --git a/chrome/browser/extensions/api/system_display/system_display_api.h b/chrome/browser/extensions/api/system_display/system_display_api.h
new file mode 100644
index 0000000..ee63e74
--- /dev/null
+++ b/chrome/browser/extensions/api/system_display/system_display_api.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_EXTENSIONS_API_SYSTEM_DISPLAY_SYSTEM_DISPLAY_API_H_
+#define CHROME_BROWSER_EXTENSIONS_API_SYSTEM_DISPLAY_SYSTEM_DISPLAY_API_H_
+
+#include <string>
+
+#include "chrome/browser/extensions/api/system_display/display_info_provider.h"
+#include "chrome/browser/extensions/extension_function.h"
+
+namespace extensions {
+
+class SystemDisplayGetInfoFunction : public AsyncExtensionFunction {
+ public:
+  DECLARE_EXTENSION_FUNCTION("system.display.getInfo",
+                             SYSTEM_DISPLAY_GETINFO);
+
+ protected:
+  virtual ~SystemDisplayGetInfoFunction() {}
+  virtual bool RunImpl() OVERRIDE;
+
+ private:
+  void OnGetDisplayInfoCompleted(bool success);
+};
+
+class SystemDisplaySetDisplayPropertiesFunction
+    : public AsyncExtensionFunction {
+ public:
+  DECLARE_EXTENSION_FUNCTION("system.display.setDisplayProperties",
+                             SYSTEM_DISPLAY_SETDISPLAYPROPERTIES);
+
+ protected:
+  virtual ~SystemDisplaySetDisplayPropertiesFunction() {}
+  virtual bool RunImpl() OVERRIDE;
+
+ private:
+  void OnPropertiesSet(bool success, const std::string& error);
+};
+
+}  // namespace extensions
+
+#endif  // CHROME_BROWSER_EXTENSIONS_API_SYSTEM_DISPLAY_SYSTEM_DISPLAY_API_H_
diff --git a/chrome/browser/extensions/api/system_info_display/system_info_display_apitest.cc b/chrome/browser/extensions/api/system_display/system_display_apitest.cc
similarity index 81%
rename from chrome/browser/extensions/api/system_info_display/system_info_display_apitest.cc
rename to chrome/browser/extensions/api/system_display/system_display_apitest.cc
index ec254d7..7880c46 100644
--- a/chrome/browser/extensions/api/system_info_display/system_info_display_apitest.cc
+++ b/chrome/browser/extensions/api/system_display/system_display_apitest.cc
@@ -1,11 +1,11 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/extensions/api/system_info_display/system_info_display_api.h"
+#include "chrome/browser/extensions/api/system_display/system_display_api.h"
 
 #include "base/strings/string_number_conversions.h"
-#include "chrome/browser/extensions/api/system_info_display/display_info_provider.h"
+#include "chrome/browser/extensions/api/system_display/display_info_provider.h"
 #include "chrome/browser/extensions/extension_apitest.h"
 #include "chrome/browser/extensions/extension_function_test_utils.h"
 
@@ -13,8 +13,8 @@
 
 namespace extensions {
 
-using api::system_info_display::Bounds;
-using api::system_info_display::DisplayUnitInfo;
+using api::system_display::Bounds;
+using api::system_display::DisplayUnitInfo;
 
 class MockDisplayInfoProvider : public DisplayInfoProvider {
  public:
@@ -55,7 +55,7 @@
 
   virtual void SetInfo(
       const std::string& display_id,
-      const api::system_info_display::DisplayProperties& params,
+      const api::system_display::DisplayProperties& params,
       const SetInfoCallback& callback) OVERRIDE {
     // Should get called only once per test case.
     EXPECT_FALSE(set_info_value_);
@@ -81,10 +81,10 @@
   DISALLOW_COPY_AND_ASSIGN(MockDisplayInfoProvider);
 };
 
-class SystemInfoDisplayApiTest: public ExtensionApiTest {
+class SystemDisplayApiTest: public ExtensionApiTest {
  public:
-  SystemInfoDisplayApiTest() {}
-  virtual ~SystemInfoDisplayApiTest() {}
+  SystemDisplayApiTest() {}
+  virtual ~SystemDisplayApiTest() {}
 
   virtual void SetUpOnMainThread() OVERRIDE {
     ExtensionApiTest::SetUpOnMainThread();
@@ -102,17 +102,17 @@
  protected:
   scoped_refptr<MockDisplayInfoProvider> provider_;
 
-  DISALLOW_COPY_AND_ASSIGN(SystemInfoDisplayApiTest);
+  DISALLOW_COPY_AND_ASSIGN(SystemDisplayApiTest);
 };
 
-IN_PROC_BROWSER_TEST_F(SystemInfoDisplayApiTest, GetDisplay) {
-  ASSERT_TRUE(RunPlatformAppTest("systeminfo/display")) << message_;
+IN_PROC_BROWSER_TEST_F(SystemDisplayApiTest, GetDisplay) {
+  ASSERT_TRUE(RunPlatformAppTest("system/display")) << message_;
 }
 
 #if !defined(OS_CHROMEOS)
-IN_PROC_BROWSER_TEST_F(SystemInfoDisplayApiTest, SetDisplay) {
-  scoped_refptr<SystemInfoDisplaySetDisplayPropertiesFunction>
-      set_info_function(new SystemInfoDisplaySetDisplayPropertiesFunction());
+IN_PROC_BROWSER_TEST_F(SystemDisplayApiTest, SetDisplay) {
+  scoped_refptr<SystemDisplaySetDisplayPropertiesFunction>
+      set_info_function(new SystemDisplaySetDisplayPropertiesFunction());
 
   set_info_function->set_has_callback(true);
 
@@ -127,7 +127,7 @@
 #endif  // !defined(OS_CHROMEOS)
 
 #if defined(OS_CHROMEOS)
-IN_PROC_BROWSER_TEST_F(SystemInfoDisplayApiTest, SetDisplayNotKioskEnabled) {
+IN_PROC_BROWSER_TEST_F(SystemDisplayApiTest, SetDisplayNotKioskEnabled) {
   scoped_ptr<base::DictionaryValue> test_extension_value(utils::ParseDictionary(
       "{\n"
       "  \"name\": \"Test\",\n"
@@ -141,8 +141,8 @@
   scoped_refptr<Extension> test_extension(
       utils::CreateExtension(test_extension_value.get()));
 
-  scoped_refptr<SystemInfoDisplaySetDisplayPropertiesFunction>
-      set_info_function(new SystemInfoDisplaySetDisplayPropertiesFunction());
+  scoped_refptr<SystemDisplaySetDisplayPropertiesFunction>
+      set_info_function(new SystemDisplaySetDisplayPropertiesFunction());
 
   set_info_function->set_extension(test_extension.get());
   set_info_function->set_has_callback(true);
@@ -156,7 +156,7 @@
   EXPECT_FALSE(set_info);
 }
 
-IN_PROC_BROWSER_TEST_F(SystemInfoDisplayApiTest, SetDisplayKioskEnabled) {
+IN_PROC_BROWSER_TEST_F(SystemDisplayApiTest, SetDisplayKioskEnabled) {
   scoped_ptr<base::DictionaryValue> test_extension_value(utils::ParseDictionary(
       "{\n"
       "  \"name\": \"Test\",\n"
@@ -171,8 +171,8 @@
   scoped_refptr<Extension> test_extension(
       utils::CreateExtension(test_extension_value.get()));
 
-  scoped_refptr<SystemInfoDisplaySetDisplayPropertiesFunction>
-      set_info_function(new SystemInfoDisplaySetDisplayPropertiesFunction());
+  scoped_refptr<SystemDisplaySetDisplayPropertiesFunction>
+      set_info_function(new SystemDisplaySetDisplayPropertiesFunction());
 
   set_info_function->set_has_callback(true);
   set_info_function->set_extension(test_extension.get());
diff --git a/chrome/browser/extensions/api/system_indicator/system_indicator_manager.cc b/chrome/browser/extensions/api/system_indicator/system_indicator_manager.cc
index f708074..4297abe 100644
--- a/chrome/browser/extensions/api/system_indicator/system_indicator_manager.cc
+++ b/chrome/browser/extensions/api/system_indicator/system_indicator_manager.cc
@@ -167,7 +167,8 @@
     return;
   }
 
-  StatusIcon* indicator_icon = status_tray_->CreateStatusIcon();
+  StatusIcon* indicator_icon =
+      status_tray_->CreateStatusIcon(StatusTray::OTHER_ICON);
   if (indicator_icon != NULL) {
     ExtensionIndicatorIcon* status_icon = new ExtensionIndicatorIcon(
         extension,
diff --git a/chrome/browser/extensions/api/system_info_display/system_info_display_api.h b/chrome/browser/extensions/api/system_info_display/system_info_display_api.h
deleted file mode 100644
index db427e5..0000000
--- a/chrome/browser/extensions/api/system_info_display/system_info_display_api.h
+++ /dev/null
@@ -1,44 +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_EXTENSIONS_API_SYSTEM_INFO_DISPLAY_SYSTEM_INFO_DISPLAY_API_H_
-#define CHROME_BROWSER_EXTENSIONS_API_SYSTEM_INFO_DISPLAY_SYSTEM_INFO_DISPLAY_API_H_
-
-#include <string>
-
-#include "chrome/browser/extensions/api/system_info_display/display_info_provider.h"
-#include "chrome/browser/extensions/extension_function.h"
-
-namespace extensions {
-
-class SystemInfoDisplayGetDisplayInfoFunction : public AsyncExtensionFunction {
- public:
-  DECLARE_EXTENSION_FUNCTION("systemInfo.display.getDisplayInfo",
-                             SYSTEMINFO_DISPLAY_GETDISPLAYINFO);
-
- protected:
-  virtual ~SystemInfoDisplayGetDisplayInfoFunction() {}
-  virtual bool RunImpl() OVERRIDE;
-
- private:
-  void OnGetDisplayInfoCompleted(bool success);
-};
-
-class SystemInfoDisplaySetDisplayPropertiesFunction
-    : public AsyncExtensionFunction {
- public:
-  DECLARE_EXTENSION_FUNCTION("systemInfo.display.setDisplayProperties",
-                             SYSTEMINFO_DISPLAY_SETDISPLAYPROPERTIES);
-
- protected:
-  virtual ~SystemInfoDisplaySetDisplayPropertiesFunction() {}
-  virtual bool RunImpl() OVERRIDE;
-
- private:
-  void OnPropertiesSet(bool success, const std::string& error);
-};
-
-}  // namespace extensions
-
-#endif  // CHROME_BROWSER_EXTENSIONS_API_SYSTEM_INFO_DISPLAY_SYSTEM_INFO_DISPLAY_API_H__
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 f05dc88..671f628 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
@@ -11,14 +11,12 @@
 #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/common/chrome_switches.h"
 #include "chrome/test/base/ui_test_utils.h"
 
 namespace {
 
 using chrome::StorageMonitor;
-using chrome::test::TestStorageMonitor;
 using extensions::api::experimental_system_info_storage::ParseStorageUnitType;
 using extensions::api::experimental_system_info_storage::StorageUnitInfo;
 using extensions::StorageInfoProvider;
@@ -87,9 +85,6 @@
 }
 
 IN_PROC_BROWSER_TEST_F(SystemInfoStorageApiTest, StorageAttachment) {
-  scoped_ptr<TestStorageMonitor> monitor(
-      TestStorageMonitor::CreateForBrowserTests());
-
   TestStorageInfoProvider* provider =
       new TestStorageInfoProvider(kRemovableStorageData,
                                   arraysize(kRemovableStorageData));
diff --git a/chrome/browser/extensions/api/system_info_storage/system_info_storage_eject_apitest.cc b/chrome/browser/extensions/api/system_info_storage/system_info_storage_eject_apitest.cc
index ba51993..7f66a00 100644
--- a/chrome/browser/extensions/api/system_info_storage/system_info_storage_eject_apitest.cc
+++ b/chrome/browser/extensions/api/system_info_storage/system_info_storage_eject_apitest.cc
@@ -35,7 +35,7 @@
 
 class SystemInfoStorageEjectApiTest : public ExtensionApiTest {
  public:
-  SystemInfoStorageEjectApiTest() {}
+  SystemInfoStorageEjectApiTest() : monitor_(NULL) {}
   virtual ~SystemInfoStorageEjectApiTest() {}
 
  protected:
@@ -45,6 +45,11 @@
     command_line->AppendSwitch(switches::kEnableExperimentalExtensionApis);
   }
 
+  virtual void SetUpOnMainThread() OVERRIDE {
+    monitor_ = chrome::test::TestStorageMonitor::CreateForBrowserTests();
+    ExtensionApiTest::SetUpOnMainThread();
+  }
+
   content::RenderViewHost* GetHost() {
     const extensions::Extension* extension =
         LoadExtension(test_data_dir_.AppendASCII("systeminfo/storage_eject"));
@@ -75,17 +80,15 @@
     content::RunAllPendingInMessageLoop();
   }
 
+ protected:
+  chrome::test::TestStorageMonitor* monitor_;
+
  private:
   DISALLOW_COPY_AND_ASSIGN(SystemInfoStorageEjectApiTest);
 };
 
 
 IN_PROC_BROWSER_TEST_F(SystemInfoStorageEjectApiTest, EjectTest) {
-  scoped_ptr<chrome::test::TestStorageMonitor> monitor(
-      chrome::test::TestStorageMonitor::CreateForBrowserTests());
-  monitor->Init();
-  monitor->MarkInitialized();
-
   TestStorageInfoProvider* provider =
       new TestStorageInfoProvider(kRemovableStorageData,
                                   arraysize(kRemovableStorageData));
@@ -104,17 +107,12 @@
   EXPECT_TRUE(attach_finished_listener.WaitUntilSatisfied());
 
   ExecuteCmdAndCheckReply(host, "ejectTest()", "eject_ok");
-  EXPECT_EQ(kRemovableStorageData[0].device_id, monitor->ejected_device());
+  EXPECT_EQ(kRemovableStorageData[0].device_id, monitor_->ejected_device());
 
   Detach();
 }
 
 IN_PROC_BROWSER_TEST_F(SystemInfoStorageEjectApiTest, EjectBadDeviceTest) {
-  scoped_ptr<chrome::test::TestStorageMonitor> monitor(
-      chrome::test::TestStorageMonitor::CreateForBrowserTests());
-  monitor->Init();
-  monitor->MarkInitialized();
-
   TestStorageInfoProvider* provider =
       new TestStorageInfoProvider(kRemovableStorageData,
                                   arraysize(kRemovableStorageData));
@@ -122,5 +120,5 @@
 
   ExecuteCmdAndCheckReply(GetHost(), "ejectFailTest()", "eject_no_such_device");
 
-  EXPECT_EQ("", monitor->ejected_device());
+  EXPECT_EQ("", monitor_->ejected_device());
 }
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 cfef6e3..4f4555d 100644
--- a/chrome/browser/extensions/api/tab_capture/tab_capture_apitest.cc
+++ b/chrome/browser/extensions/api/tab_capture/tab_capture_apitest.cc
@@ -43,7 +43,13 @@
 
 }  // namespace
 
-IN_PROC_BROWSER_TEST_F(TabCaptureApiTest, ApiTests) {
+// http://crbug.com/261493
+#if defined(OS_LINUX) || defined(OS_CHROMEOS)
+#define MAYBE_ApiTests DISABLED_ApiTests
+#else
+#define MAYBE_ApiTests ApiTests
+#endif
+IN_PROC_BROWSER_TEST_F(TabCaptureApiTest, MAYBE_ApiTests) {
   extensions::FeatureSwitch::ScopedOverride tab_capture(
       extensions::FeatureSwitch::tab_capture(), true);
 
diff --git a/chrome/browser/extensions/api/tabs/tabs_api.cc b/chrome/browser/extensions/api/tabs/tabs_api.cc
index 673f4b7..fcccd07 100644
--- a/chrome/browser/extensions/api/tabs/tabs_api.cc
+++ b/chrome/browser/extensions/api/tabs/tabs_api.cc
@@ -62,7 +62,6 @@
 #include "chrome/common/extensions/incognito_handler.h"
 #include "chrome/common/extensions/message_bundle.h"
 #include "chrome/common/extensions/permissions/permissions_data.h"
-#include "chrome/common/extensions/user_script.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/translate/language_detection_details.h"
 #include "chrome/common/url_constants.h"
@@ -80,6 +79,7 @@
 #include "extensions/browser/file_reader.h"
 #include "extensions/common/constants.h"
 #include "extensions/common/error_utils.h"
+#include "extensions/common/user_script.h"
 #include "skia/ext/image_operations.h"
 #include "skia/ext/platform_canvas.h"
 #include "third_party/skia/include/core/SkBitmap.h"
diff --git a/chrome/browser/extensions/api/tabs/tabs_api.h b/chrome/browser/extensions/api/tabs/tabs_api.h
index 15f47eb..1313b71 100644
--- a/chrome/browser/extensions/api/tabs/tabs_api.h
+++ b/chrome/browser/extensions/api/tabs/tabs_api.h
@@ -12,10 +12,10 @@
 #include "chrome/browser/extensions/api/execute_code_function.h"
 #include "chrome/browser/extensions/extension_function.h"
 #include "chrome/common/extensions/api/tabs.h"
-#include "chrome/common/extensions/user_script.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
 #include "extensions/common/extension_resource.h"
+#include "extensions/common/user_script.h"
 #include "url/gurl.h"
 
 class BackingStore;
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 5f70e7a..e62f3f9 100644
--- a/chrome/browser/extensions/api/web_navigation/web_navigation_apitest.cc
+++ b/chrome/browser/extensions/api/web_navigation/web_navigation_apitest.cc
@@ -24,7 +24,6 @@
 #include "chrome/browser/tab_contents/render_view_context_menu.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "chrome/common/chrome_switches.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/render_process_host.h"
@@ -36,11 +35,12 @@
 #include "content/public/common/context_menu_params.h"
 #include "content/public/common/url_constants.h"
 #include "content/public/test/browser_test_utils.h"
+#include "extensions/common/switches.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"
+#include "webkit/common/resource_type.h"
 
 using content::WebContents;
 
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 4e9ea49..e0339fc 100644
--- a/chrome/browser/extensions/api/web_request/web_request_api.h
+++ b/chrome/browser/extensions/api/web_request/web_request_api.h
@@ -25,7 +25,7 @@
 #include "net/base/completion_callback.h"
 #include "net/base/network_delegate.h"
 #include "net/http/http_request_headers.h"
-#include "webkit/glue/resource_type.h"
+#include "webkit/common/resource_type.h"
 
 class ExtensionInfoMap;
 class ExtensionWebRequestTimeTracker;
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 9b849c1..90b2f84 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
@@ -20,7 +20,7 @@
 #include "net/http/http_request_headers.h"
 #include "net/http/http_response_headers.h"
 #include "url/gurl.h"
-#include "webkit/glue/resource_type.h"
+#include "webkit/common/resource_type.h"
 
 namespace base {
 class ListValue;
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 f64add1..0655d6e 100644
--- a/chrome/browser/extensions/api/webstore_private/webstore_private_api.cc
+++ b/chrome/browser/extensions/api/webstore_private/webstore_private_api.cc
@@ -566,7 +566,7 @@
     // Show the app list to show download is progressing. Don't show the app
     // list on first app install so users can be trained to open it themselves.
     if (approval_->manifest->is_app() && !approval_->enable_launcher)
-      AppListService::Get()->ShowAppList(profile());
+      AppListService::Get()->ShowForProfile(profile());
   }
 
   // The extension will install through the normal extension install flow, but
diff --git a/chrome/browser/extensions/app_process_apitest.cc b/chrome/browser/extensions/app_process_apitest.cc
index 7f4dd7b..ee5a829 100644
--- a/chrome/browser/extensions/app_process_apitest.cc
+++ b/chrome/browser/extensions/app_process_apitest.cc
@@ -31,6 +31,10 @@
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "sync/api/string_ordinal.h"
 
+#if defined(OS_WIN) && defined(USE_ASH)
+#include "base/win/windows_version.h"
+#endif
+
 using content::NavigationController;
 using content::RenderViewHost;
 using content::WebContents;
@@ -599,6 +603,12 @@
 // empty.html) results in the new window being in an app process. See
 // http://crbug.com/89272 for more details.
 IN_PROC_BROWSER_TEST_F(AppApiTest, OpenAppFromIframe) {
+#if defined(OS_WIN) && defined(USE_ASH)
+  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
+  if (base::win::GetVersion() >= base::win::VERSION_WIN8)
+    return;
+#endif
+
   extensions::ProcessMap* process_map = extensions::ExtensionSystem::Get(
       browser()->profile())->extension_service()->process_map();
 
diff --git a/chrome/browser/extensions/blacklist_unittest.cc b/chrome/browser/extensions/blacklist_unittest.cc
index ad52f41..1ccaf4c 100644
--- a/chrome/browser/extensions/blacklist_unittest.cc
+++ b/chrome/browser/extensions/blacklist_unittest.cc
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 #include "base/bind.h"
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "chrome/browser/extensions/blacklist.h"
 #include "chrome/browser/extensions/extension_prefs.h"
diff --git a/chrome/browser/extensions/component_loader.cc b/chrome/browser/extensions/component_loader.cc
index 152e92f..1c4fe8d 100644
--- a/chrome/browser/extensions/component_loader.cc
+++ b/chrome/browser/extensions/component_loader.cc
@@ -452,6 +452,9 @@
 
     Add(IDR_NETWORK_CONFIGURATION_MANIFEST,
         base::FilePath(FILE_PATH_LITERAL("chromeos/network_configuration")));
+
+    Add(IDR_CONNECTIVITY_DIAGNOSTICS_MANIFEST,
+        base::FilePath(extension_misc::kConnectivityDiagnosticsPath));
   }
 
   // Load ChromeVox extension now if spoken feedback is enabled.
diff --git a/chrome/browser/extensions/convert_user_script.cc b/chrome/browser/extensions/convert_user_script.cc
index 0d79540..f6fbea7 100644
--- a/chrome/browser/extensions/convert_user_script.cc
+++ b/chrome/browser/extensions/convert_user_script.cc
@@ -20,9 +20,9 @@
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_file_util.h"
 #include "chrome/common/extensions/extension_manifest_constants.h"
-#include "chrome/common/extensions/user_script.h"
 #include "crypto/sha2.h"
 #include "extensions/common/constants.h"
+#include "extensions/common/user_script.h"
 #include "url/gurl.h"
 
 namespace keys = extension_manifest_keys;
diff --git a/chrome/browser/extensions/convert_web_app_browsertest.cc b/chrome/browser/extensions/convert_web_app_browsertest.cc
index c9ed528..f094e14 100644
--- a/chrome/browser/extensions/convert_web_app_browsertest.cc
+++ b/chrome/browser/extensions/convert_web_app_browsertest.cc
@@ -24,6 +24,10 @@
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/browser_test_utils.h"
 
+#if defined(OS_WIN) && defined(USE_ASH)
+#include "base/win/windows_version.h"
+#endif
+
 namespace extensions {
 
 class ExtensionFromWebAppTest
@@ -59,6 +63,12 @@
 #endif
 
 IN_PROC_BROWSER_TEST_F(ExtensionFromWebAppTest, MAYBE_Basic) {
+#if defined(OS_WIN) && defined(USE_ASH)
+  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
+  if (base::win::GetVersion() >= base::win::VERSION_WIN8)
+    return;
+#endif
+
   browser()->profile()->GetExtensionService()->set_show_extensions_prompts(
       false);
 
diff --git a/chrome/browser/extensions/crx_installer.cc b/chrome/browser/extensions/crx_installer.cc
index 2d2e0ae..588e2f1 100644
--- a/chrome/browser/extensions/crx_installer.cc
+++ b/chrome/browser/extensions/crx_installer.cc
@@ -41,11 +41,11 @@
 #include "chrome/common/extensions/manifest.h"
 #include "chrome/common/extensions/manifest_handlers/shared_module_info.h"
 #include "chrome/common/extensions/manifest_url_handler.h"
-#include "chrome/common/extensions/user_script.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/resource_dispatcher_host.h"
 #include "content/public/browser/user_metrics.h"
+#include "extensions/common/user_script.h"
 #include "grit/chromium_strings.h"
 #include "grit/generated_resources.h"
 #include "grit/theme_resources.h"
diff --git a/chrome/browser/extensions/default_apps_unittest.cc b/chrome/browser/extensions/default_apps_unittest.cc
index 1104e7b..1f16f2d 100644
--- a/chrome/browser/extensions/default_apps_unittest.cc
+++ b/chrome/browser/extensions/default_apps_unittest.cc
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 #include "base/memory/scoped_ptr.h"
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "base/prefs/pref_service.h"
 #include "chrome/browser/extensions/default_apps.h"
 #include "chrome/browser/extensions/external_pref_loader.h"
diff --git a/chrome/browser/extensions/event_names.cc b/chrome/browser/extensions/event_names.cc
index 3270043..c5eeeba 100644
--- a/chrome/browser/extensions/event_names.cc
+++ b/chrome/browser/extensions/event_names.cc
@@ -71,7 +71,7 @@
 
 const char kOnPushMessage[] = "pushMessaging.onMessage";
 
-const char kOnDisplayChanged[] = "systemInfo.display.onDisplayChanged";
+const char kOnDisplayChanged[] = "system.display.onDisplayChanged";
 const char kOnStorageAvailableCapacityChanged[] =
     "experimental.systemInfo.storage.onAvailableCapacityChanged";
 const char kOnStorageAttached[] = "experimental.systemInfo.storage.onAttached";
diff --git a/chrome/browser/extensions/event_router.cc b/chrome/browser/extensions/event_router.cc
index bcb7c2a..e3673d5 100644
--- a/chrome/browser/extensions/event_router.cc
+++ b/chrome/browser/extensions/event_router.cc
@@ -8,7 +8,7 @@
 
 #include "base/bind.h"
 #include "base/command_line.h"
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "base/stl_util.h"
 #include "base/values.h"
 #include "base/version.h"
@@ -492,6 +492,18 @@
   DispatchEventImpl(extension_id, linked_ptr<Event>(event.release()));
 }
 
+void EventRouter::DispatchEventWithLazyListener(const std::string& extension_id,
+                                                scoped_ptr<Event> event) {
+  DCHECK(!extension_id.empty());
+  std::string event_name = event->event_name;
+  bool has_listener = ExtensionHasEventListener(extension_id, event_name);
+  if (!has_listener)
+    AddLazyEventListener(event_name, extension_id);
+  DispatchEventToExtension(extension_id, event.Pass());
+  if (!has_listener)
+    RemoveLazyEventListener(event_name, extension_id);
+}
+
 void EventRouter::DispatchEventImpl(const std::string& restrict_to_extension_id,
                                     const linked_ptr<Event>& event) {
   // We don't expect to get events from a completely different profile.
diff --git a/chrome/browser/extensions/event_router.h b/chrome/browser/extensions/event_router.h
index 16f64e9..cd1ea1d 100644
--- a/chrome/browser/extensions/event_router.h
+++ b/chrome/browser/extensions/event_router.h
@@ -143,6 +143,13 @@
   virtual void DispatchEventToExtension(const std::string& extension_id,
                                         scoped_ptr<Event> event);
 
+  // Dispatches |event| to the given extension as if the extension has a lazy
+  // listener for it. NOTE: This should be used rarely, for dispatching events
+  // to extensions that haven't had a chance to add their own listeners yet, eg:
+  // newly installed extensions.
+  void DispatchEventWithLazyListener(const std::string& extension_id,
+                                     scoped_ptr<Event> event);
+
   // Record the Event Ack from the renderer. (One less event in-flight.)
   void OnEventAck(Profile* profile, const std::string& extension_id);
 
diff --git a/chrome/browser/extensions/event_router_forwarder_unittest.cc b/chrome/browser/extensions/event_router_forwarder_unittest.cc
index bb80d11..c77ecbf 100644
--- a/chrome/browser/extensions/event_router_forwarder_unittest.cc
+++ b/chrome/browser/extensions/event_router_forwarder_unittest.cc
@@ -5,7 +5,7 @@
 #include "chrome/browser/extensions/event_router_forwarder.h"
 
 #include "base/bind.h"
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "base/power_monitor/power_monitor.h"
 #include "base/test/thread_test_helper.h"
 #include "chrome/browser/profiles/profile_manager.h"
diff --git a/chrome/browser/extensions/extension_action.cc b/chrome/browser/extensions/extension_action.cc
index 264c548..7d3ecd1 100644
--- a/chrome/browser/extensions/extension_action.cc
+++ b/chrome/browser/extensions/extension_action.cc
@@ -8,7 +8,7 @@
 
 #include "base/bind.h"
 #include "base/logging.h"
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "chrome/common/badge_util.h"
 #include "chrome/common/extensions/extension_constants.h"
 #include "chrome/common/icon_with_badge_image_source.h"
diff --git a/chrome/browser/extensions/extension_action_icon_factory_unittest.cc b/chrome/browser/extensions/extension_action_icon_factory_unittest.cc
index 5e9d952..39ea0d6 100644
--- a/chrome/browser/extensions/extension_action_icon_factory_unittest.cc
+++ b/chrome/browser/extensions/extension_action_icon_factory_unittest.cc
@@ -7,7 +7,7 @@
 #include "base/command_line.h"
 #include "base/file_util.h"
 #include "base/json/json_file_value_serializer.h"
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "base/path_service.h"
 #include "chrome/browser/extensions/extension_action.h"
 #include "chrome/browser/extensions/extension_action_manager.h"
diff --git a/chrome/browser/extensions/extension_action_unittest.cc b/chrome/browser/extensions/extension_action_unittest.cc
index 7656b46..c71e7b1 100644
--- a/chrome/browser/extensions/extension_action_unittest.cc
+++ b/chrome/browser/extensions/extension_action_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "chrome/browser/extensions/extension_action.h"
 #include "chrome/common/extensions/api/extension_action/action_info.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/browser/extensions/extension_disabled_ui.cc b/chrome/browser/extensions/extension_disabled_ui.cc
index 07f7555..d1c3b5c 100644
--- a/chrome/browser/extensions/extension_disabled_ui.cc
+++ b/chrome/browser/extensions/extension_disabled_ui.cc
@@ -10,7 +10,7 @@
 #include "base/lazy_instance.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "base/metrics/histogram.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/app/chrome_command_ids.h"
diff --git a/chrome/browser/extensions/extension_error_reporter.cc b/chrome/browser/extensions/extension_error_reporter.cc
index d94fd81..6448712 100644
--- a/chrome/browser/extensions/extension_error_reporter.cc
+++ b/chrome/browser/extensions/extension_error_reporter.cc
@@ -9,7 +9,7 @@
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/logging.h"
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/ui/simple_message_box.h"
 
diff --git a/chrome/browser/extensions/extension_function_dispatcher.cc b/chrome/browser/extensions/extension_function_dispatcher.cc
index 14e384a..47241e9 100644
--- a/chrome/browser/extensions/extension_function_dispatcher.cc
+++ b/chrome/browser/extensions/extension_function_dispatcher.cc
@@ -36,13 +36,11 @@
 #include "content/public/common/result_codes.h"
 #include "ipc/ipc_message.h"
 #include "ipc/ipc_message_macros.h"
-#include "third_party/WebKit/public/web/WebSecurityOrigin.h"
-#include "webkit/glue/resource_type.h"
+#include "webkit/common/resource_type.h"
 
 using extensions::Extension;
 using extensions::ExtensionAPI;
 using content::RenderViewHost;
-using WebKit::WebSecurityOrigin;
 
 namespace {
 
@@ -362,9 +360,7 @@
   const Extension* extension = service->extensions()->GetByID(
       params.extension_id);
   if (!extension)
-    extension = service->extensions()->GetHostedAppByURL(ExtensionURLInfo(
-        WebSecurityOrigin::createFromString(params.source_origin),
-        params.source_url));
+    extension = service->extensions()->GetHostedAppByURL(params.source_url);
 
   scoped_refptr<ExtensionFunction> function(
       CreateExtensionFunction(params, extension,
diff --git a/chrome/browser/extensions/extension_function_histogram_value.h b/chrome/browser/extensions/extension_function_histogram_value.h
index 0bf7f56..2bc33fc 100644
--- a/chrome/browser/extensions/extension_function_histogram_value.h
+++ b/chrome/browser/extensions/extension_function_histogram_value.h
@@ -122,7 +122,7 @@
   APP_CURRENTWINDOWINTERNAL_SHOW,
   WEBSTOREPRIVATE_GETBROWSERLOGIN,
   EXPERIMENTAL_IDENTITY_GETAUTHTOKEN,
-  SYSTEMINFO_DISPLAY_GETDISPLAYINFO,
+  DELETED_SYSTEMINFO_DISPLAY_GETDISPLAYINFO,
   BROWSINGDATA_REMOVEPLUGINDATA,
   SOCKET_LISTEN,
   MEDIAGALLERIES_GETMEDIAFILESYSTEMS,
@@ -548,7 +548,7 @@
   SYSTEMINFO_MEMORY_GET,
   ACTIVITYLOGPRIVATE_GETEXTENSIONACTIVITIES,
   RUNTIME_GETPACKAGEDIRECTORYENTRY,
-  SYSTEMINFO_DISPLAY_SETDISPLAYPROPERTIES,
+  DELETED_SYSTEMINFO_DISPLAY_SETDISPLAYPROPERTIES,
   FEEDBACKPRIVATE_GETUSEREMAIL,
   FEEDBACKPRIVATE_GETSYSTEMINFORMATION,
   FEEDBACKPRIVATE_SENDFEEDBACK,
@@ -567,6 +567,9 @@
   TYPES_PRIVATE_CHROMEDIRECTSETTING_CLEAR,
   EXPERIMENTAL_SYSTEMINFO_STORAGE_EJECTDEVICE,
   SYSTEM_CPU_GETINFO,
+  BOOKMARKMANAGERPRIVATE_REMOVETREES,
+  SYSTEM_DISPLAY_GETINFO,
+  SYSTEM_DISPLAY_SETDISPLAYPROPERTIES,
   ENUM_BOUNDARY // Last entry: Add new entries above.
 };
 
diff --git a/chrome/browser/extensions/extension_host.cc b/chrome/browser/extensions/extension_host.cc
index e945bad..f6462a2 100644
--- a/chrome/browser/extensions/extension_host.cc
+++ b/chrome/browser/extensions/extension_host.cc
@@ -9,7 +9,7 @@
 #include "base/bind.h"
 #include "base/memory/singleton.h"
 #include "base/memory/weak_ptr.h"
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "base/metrics/histogram.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
diff --git a/chrome/browser/extensions/extension_icon_image_unittest.cc b/chrome/browser/extensions/extension_icon_image_unittest.cc
index 13706bd..346a2ff 100644
--- a/chrome/browser/extensions/extension_icon_image_unittest.cc
+++ b/chrome/browser/extensions/extension_icon_image_unittest.cc
@@ -5,7 +5,7 @@
 #include "chrome/browser/extensions/extension_icon_image.h"
 
 #include "base/json/json_file_value_serializer.h"
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "base/path_service.h"
 #include "chrome/browser/extensions/image_loader.h"
 #include "chrome/common/chrome_paths.h"
diff --git a/chrome/browser/extensions/extension_icon_manager_unittest.cc b/chrome/browser/extensions/extension_icon_manager_unittest.cc
index d092c2d..287f98b 100644
--- a/chrome/browser/extensions/extension_icon_manager_unittest.cc
+++ b/chrome/browser/extensions/extension_icon_manager_unittest.cc
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 #include "base/json/json_file_value_serializer.h"
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "base/path_service.h"
 #include "base/values.h"
 #include "chrome/browser/extensions/extension_icon_manager.h"
diff --git a/chrome/browser/extensions/extension_icon_source_apitest.cc b/chrome/browser/extensions/extension_icon_source_apitest.cc
index 8406ed7..db7a808 100644
--- a/chrome/browser/extensions/extension_icon_source_apitest.cc
+++ b/chrome/browser/extensions/extension_icon_source_apitest.cc
@@ -8,10 +8,10 @@
 #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_switches.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/browser_test_utils.h"
+#include "extensions/common/switches.h"
 #include "net/dns/mock_host_resolver.h"
 #include "url/gurl.h"
 
@@ -19,7 +19,8 @@
  protected:
   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
     ExtensionApiTest::SetUpCommandLine(command_line);
-    command_line->AppendSwitch(switches::kAllowLegacyExtensionManifests);
+    command_line->AppendSwitch(
+        extensions::switches::kAllowLegacyExtensionManifests);
   }
 };
 
diff --git a/chrome/browser/extensions/extension_info_map_unittest.cc b/chrome/browser/extensions/extension_info_map_unittest.cc
index 3fbefc4..10dace7 100644
--- a/chrome/browser/extensions/extension_info_map_unittest.cc
+++ b/chrome/browser/extensions/extension_info_map_unittest.cc
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 #include "base/json/json_file_value_serializer.h"
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "base/path_service.h"
 #include "chrome/browser/extensions/extension_info_map.h"
 #include "chrome/common/chrome_paths.h"
@@ -11,15 +11,11 @@
 #include "chrome/common/extensions/extension_manifest_constants.h"
 #include "content/public/test/test_browser_thread.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/WebKit/public/platform/WebString.h"
-#include "third_party/WebKit/public/platform/WebURL.h"
 
 using content::BrowserThread;
 using extensions::APIPermission;
 using extensions::Extension;
 using extensions::Manifest;
-using WebKit::WebSecurityOrigin;
-using WebKit::WebString;
 
 namespace keys = extension_manifest_keys;
 
@@ -139,8 +135,6 @@
                                                   "tabs_extension.json"));
 
   GURL app_url("http://www.google.com/mail/foo.html");
-  WebSecurityOrigin app_origin = WebSecurityOrigin::create(
-      GURL("http://www.google.com/mail/foo.html"));
   ASSERT_TRUE(app->is_app());
   ASSERT_TRUE(app->web_extent().MatchesURL(app_url));
 
@@ -150,11 +144,10 @@
   // The app should have the notifications permission, either from a
   // chrome-extension URL or from its web extent.
   const Extension* match = info_map->extensions().GetExtensionOrAppByURL(
-      ExtensionURLInfo(app_origin, app->GetResourceURL("a.html")));
+      app->GetResourceURL("a.html"));
   EXPECT_TRUE(match &&
       match->HasAPIPermission(APIPermission::kNotification));
-  match = info_map->extensions().GetExtensionOrAppByURL(
-      ExtensionURLInfo(app_origin, app_url));
+  match = info_map->extensions().GetExtensionOrAppByURL(app_url);
   EXPECT_TRUE(match &&
       match->HasAPIPermission(APIPermission::kNotification));
   EXPECT_FALSE(match &&
@@ -162,7 +155,7 @@
 
   // The extension should have the tabs permission.
   match = info_map->extensions().GetExtensionOrAppByURL(
-      ExtensionURLInfo(app_origin, extension->GetResourceURL("a.html")));
+      extension->GetResourceURL("a.html"));
   EXPECT_TRUE(match &&
       match->HasAPIPermission(APIPermission::kTab));
   EXPECT_FALSE(match &&
@@ -170,14 +163,7 @@
 
   // Random URL should not have any permissions.
   GURL evil_url("http://evil.com/a.html");
-  match = info_map->extensions().GetExtensionOrAppByURL(
-      ExtensionURLInfo(WebSecurityOrigin::create(evil_url), evil_url));
-  EXPECT_FALSE(match);
-
-  // Sandboxed origins should not have any permissions.
-  match = info_map->extensions().GetExtensionOrAppByURL(ExtensionURLInfo(
-      WebSecurityOrigin::createFromString(WebString::fromUTF8("null")),
-      app_url));
+  match = info_map->extensions().GetExtensionOrAppByURL(evil_url);
   EXPECT_FALSE(match);
 }
 
diff --git a/chrome/browser/extensions/extension_infobar_delegate.cc b/chrome/browser/extensions/extension_infobar_delegate.cc
index 0bcedd3..a752583 100644
--- a/chrome/browser/extensions/extension_infobar_delegate.cc
+++ b/chrome/browser/extensions/extension_infobar_delegate.cc
@@ -30,7 +30,7 @@
                                       int height) {
   infobar_service->AddInfoBar(scoped_ptr<InfoBarDelegate>(
       new ExtensionInfoBarDelegate(browser, infobar_service, extension, url,
-                                   height)));
+                                   infobar_service->web_contents(), height)));
 }
 
 ExtensionInfoBarDelegate::ExtensionInfoBarDelegate(
@@ -38,6 +38,7 @@
     InfoBarService* infobar_service,
     const extensions::Extension* extension,
     const GURL& url,
+    content::WebContents* web_contents,
     int height)
     : InfoBarDelegate(infobar_service),
 #if defined(TOOLKIT_VIEWS)
@@ -49,23 +50,21 @@
   ExtensionProcessManager* manager =
       extensions::ExtensionSystem::Get(browser->profile())->process_manager();
   extension_host_.reset(manager->CreateInfobarHost(url, browser));
-  extension_host_->SetAssociatedWebContents(infobar_service->web_contents());
+  extension_host_->SetAssociatedWebContents(web_contents);
 
   registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_HOST_VIEW_SHOULD_CLOSE,
                  content::Source<Profile>(browser->profile()));
   registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED,
                  content::Source<Profile>(browser->profile()));
 
-#if defined(TOOLKIT_VIEWS) || defined(TOOLKIT_GTK)
+#if defined(TOOLKIT_VIEWS) || defined(TOOLKIT_GTK) || defined(OS_ANDROID)
+  // TODO(dtrainor): On Android, this is not used.  Might need to pull this from
+  // Android UI level in the future.  Tracked via issue 115303.
   int default_height = InfoBar::kDefaultBarTargetHeight;
 #elif defined(OS_MACOSX)
   // TODO(pkasting): Once Infobars have been ported to Mac, we can remove the
   // ifdefs and just use the Infobar constant below.
   int default_height = 36;
-#elif defined(OS_ANDROID)
-  // TODO(dtrainor): This is not used.  Might need to pull this from Android UI
-  // level in the future.  Tracked via issue 115303.
-  int default_height = 36;
 #endif
   height_ = std::max(0, height);
   height_ = std::min(2 * default_height, height_);
diff --git a/chrome/browser/extensions/extension_infobar_delegate.h b/chrome/browser/extensions/extension_infobar_delegate.h
index a8a2f62..0d549d7 100644
--- a/chrome/browser/extensions/extension_infobar_delegate.h
+++ b/chrome/browser/extensions/extension_infobar_delegate.h
@@ -35,7 +35,7 @@
 
   virtual ~ExtensionInfoBarDelegate();
 
-  // Creates an extension delegate and adds it to |infobar_service|.
+  // Creates an extension infobar delegate and adds it to |infobar_service|.
   static void Create(InfoBarService* infobar_service,
                      Browser* browser,
                      const extensions::Extension* extension,
@@ -55,6 +55,7 @@
                            InfoBarService* infobar_service,
                            const extensions::Extension* extension,
                            const GURL& url,
+                           content::WebContents* web_contents,
                            int height);
 
   // InfoBarDelegate:
diff --git a/chrome/browser/extensions/extension_install_prompt.cc b/chrome/browser/extensions/extension_install_prompt.cc
index 66521c4..e0c2f6f 100644
--- a/chrome/browser/extensions/extension_install_prompt.cc
+++ b/chrome/browser/extensions/extension_install_prompt.cc
@@ -7,7 +7,7 @@
 #include <map>
 
 #include "base/command_line.h"
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "base/prefs/pref_service.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
diff --git a/chrome/browser/extensions/extension_install_ui_browsertest.cc b/chrome/browser/extensions/extension_install_ui_browsertest.cc
index cc059f1..d5b86ee 100644
--- a/chrome/browser/extensions/extension_install_ui_browsertest.cc
+++ b/chrome/browser/extensions/extension_install_ui_browsertest.cc
@@ -8,7 +8,7 @@
 #include "chrome/browser/extensions/extension_browsertest.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/extension_sorting.h"
-#include "chrome/browser/extensions/theme_installed_infobar_delegate.h"
+#include "chrome/browser/infobars/confirm_infobar_delegate.h"
 #include "chrome/browser/infobars/infobar_service.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/themes/theme_service.h"
@@ -24,6 +24,10 @@
 #include "content/public/test/browser_test_utils.h"
 #include "extensions/common/id_util.h"
 
+#if defined(OS_WIN) && defined(USE_ASH)
+#include "base/win/windows_version.h"
+#endif
+
 using content::WebContents;
 using extensions::Extension;
 
@@ -70,6 +74,12 @@
 
 IN_PROC_BROWSER_TEST_F(ExtensionInstallUIBrowserTest,
                        MAYBE_TestThemeInstallUndoResetsToDefault) {
+#if defined(OS_WIN) && defined(USE_ASH)
+  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
+  if (base::win::GetVersion() >= base::win::VERSION_WIN8)
+    return;
+#endif
+
   // Install theme once and undo to verify we go back to default theme.
   base::FilePath theme_crx = PackExtension(test_data_dir_.AppendASCII("theme"));
   ASSERT_TRUE(InstallExtensionWithUIAutoConfirm(theme_crx, 1, browser()));
@@ -94,6 +104,12 @@
 
 IN_PROC_BROWSER_TEST_F(ExtensionInstallUIBrowserTest,
                        TestThemeInstallUndoResetsToPreviousTheme) {
+#if defined(OS_WIN) && defined(USE_ASH)
+  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
+  if (base::win::GetVersion() >= base::win::VERSION_WIN8)
+    return;
+#endif
+
   // Install first theme.
   InstallThemeAndVerify("theme", "camo theme");
   const Extension* theme = GetTheme();
diff --git a/chrome/browser/extensions/extension_nacl_browsertest.cc b/chrome/browser/extensions/extension_nacl_browsertest.cc
index 160c9f8..df151de 100644
--- a/chrome/browser/extensions/extension_nacl_browsertest.cc
+++ b/chrome/browser/extensions/extension_nacl_browsertest.cc
@@ -20,9 +20,9 @@
 #include "chrome/test/base/ui_test_utils.h"
 #include "content/public/browser/plugin_service.h"
 #include "content/public/browser/web_contents.h"
+#include "content/public/common/webplugininfo.h"
 #include "content/public/test/browser_test_utils.h"
 #include "net/dns/mock_host_resolver.h"
-#include "webkit/plugins/webplugininfo.h"
 
 using content::PluginService;
 using content::WebContents;
@@ -107,7 +107,7 @@
   bool IsNaClPluginLoaded() {
     base::FilePath path;
     if (PathService::Get(chrome::FILE_NACL_PLUGIN, &path)) {
-      webkit::WebPluginInfo info;
+      content::WebPluginInfo info;
       return PluginService::GetInstance()->GetPluginInfoByPath(path, &info);
     }
     return false;
diff --git a/chrome/browser/extensions/extension_prefs.cc b/chrome/browser/extensions/extension_prefs.cc
index ab300ff..904527d 100644
--- a/chrome/browser/extensions/extension_prefs.cc
+++ b/chrome/browser/extensions/extension_prefs.cc
@@ -26,13 +26,13 @@
 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
 #include "chrome/common/extensions/permissions/permission_set.h"
 #include "chrome/common/extensions/permissions/permissions_info.h"
-#include "chrome/common/extensions/user_script.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 "extensions/browser/pref_names.h"
 #include "extensions/common/url_pattern.h"
+#include "extensions/common/user_script.h"
 #include "grit/generated_resources.h"
 #include "ui/base/l10n/l10n_util.h"
 
@@ -538,7 +538,9 @@
   const ListValue* api_values = NULL;
   std::string api_pref = JoinPrefs(pref_key, kPrefAPIs);
   if (ReadPrefAsList(extension_id, api_pref, &api_values)) {
-    APIPermissionSet::ParseFromJSON(api_values, &apis, NULL, NULL);
+    APIPermissionSet::ParseFromJSON(api_values,
+                                    APIPermissionSet::kAllowInternalPermissions,
+                                    &apis, NULL, NULL);
   }
 
   // Retrieve the explicit host permissions.
diff --git a/chrome/browser/extensions/extension_prefs_unittest.h b/chrome/browser/extensions/extension_prefs_unittest.h
index 0f42488..fc0ae8e 100644
--- a/chrome/browser/extensions/extension_prefs_unittest.h
+++ b/chrome/browser/extensions/extension_prefs_unittest.h
@@ -5,7 +5,7 @@
 #ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_PREFS_UNITTEST_H_
 #define CHROME_BROWSER_EXTENSIONS_EXTENSION_PREFS_UNITTEST_H_
 
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "chrome/browser/extensions/test_extension_prefs.h"
 #include "content/public/test/test_browser_thread.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/browser/extensions/extension_process_manager.cc b/chrome/browser/extensions/extension_process_manager.cc
index b18b2af..ae861fa 100644
--- a/chrome/browser/extensions/extension_process_manager.cc
+++ b/chrome/browser/extensions/extension_process_manager.cc
@@ -8,7 +8,7 @@
 #include "base/command_line.h"
 #include "base/lazy_instance.h"
 #include "base/logging.h"
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "base/metrics/histogram.h"
 #include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
@@ -856,8 +856,8 @@
     const GURL& url) {
   ExtensionService* service = GetProfile()->GetExtensionService();
   if (service) {
-    const Extension* extension = service->extensions()->GetExtensionOrAppByURL(
-        ExtensionURLInfo(url));
+    const Extension* extension =
+        service->extensions()->GetExtensionOrAppByURL(url);
     if (extension &&
         !extensions::IncognitoInfo::IsSplitMode(extension)) {
       return original_manager_->GetSiteInstanceForURL(url);
diff --git a/chrome/browser/extensions/extension_protocols.cc b/chrome/browser/extensions/extension_protocols.cc
index 5bb7a98..2ec1145 100644
--- a/chrome/browser/extensions/extension_protocols.cc
+++ b/chrome/browser/extensions/extension_protocols.cc
@@ -13,7 +13,7 @@
 #include "base/format_macros.h"
 #include "base/logging.h"
 #include "base/memory/weak_ptr.h"
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "base/path_service.h"
 #include "base/sha1.h"
 #include "base/strings/string_util.h"
diff --git a/chrome/browser/extensions/extension_protocols_unittest.cc b/chrome/browser/extensions/extension_protocols_unittest.cc
index b096d98..0e41a0d 100644
--- a/chrome/browser/extensions/extension_protocols_unittest.cc
+++ b/chrome/browser/extensions/extension_protocols_unittest.cc
@@ -5,7 +5,7 @@
 #include <string>
 
 #include "base/file_util.h"
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "base/strings/string_util.h"
 #include "base/values.h"
 #include "chrome/browser/extensions/extension_info_map.h"
diff --git a/chrome/browser/extensions/extension_resource_request_policy_apitest.cc b/chrome/browser/extensions/extension_resource_request_policy_apitest.cc
index 05e3588..3eea53c 100644
--- a/chrome/browser/extensions/extension_resource_request_policy_apitest.cc
+++ b/chrome/browser/extensions/extension_resource_request_policy_apitest.cc
@@ -6,10 +6,10 @@
 #include "chrome/browser/extensions/extension_apitest.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "chrome/common/chrome_switches.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/browser_test_utils.h"
+#include "extensions/common/switches.h"
 #include "net/dns/mock_host_resolver.h"
 #include "url/gurl.h"
 
@@ -17,7 +17,8 @@
  protected:
   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
     ExtensionApiTest::SetUpCommandLine(command_line);
-    command_line->AppendSwitch(switches::kAllowLegacyExtensionManifests);
+    command_line->AppendSwitch(
+        extensions::switches::kAllowLegacyExtensionManifests);
   }
 };
 
diff --git a/chrome/browser/extensions/extension_service.cc b/chrome/browser/extensions/extension_service.cc
index 73a7c63..e3ae629 100644
--- a/chrome/browser/extensions/extension_service.cc
+++ b/chrome/browser/extensions/extension_service.cc
@@ -264,8 +264,7 @@
 }
 
 const Extension* ExtensionService::GetInstalledApp(const GURL& url) const {
-  const Extension* extension = extensions_.GetExtensionOrAppByURL(
-      ExtensionURLInfo(url));
+  const Extension* extension = extensions_.GetExtensionOrAppByURL(url);
   return (extension && extension->is_app()) ? extension : NULL;
 }
 
@@ -704,6 +703,8 @@
     }
 
     path = current_extension->path();
+    // BeingUpgraded is set back to false when the extension is added.
+    SetBeingUpgraded(current_extension, true);
     DisableExtension(extension_id, Extension::DISABLE_RELOAD);
     reloading_extensions_.insert(extension_id);
   } else {
@@ -2584,15 +2585,13 @@
 
 bool ExtensionService::ExtensionBindingsAllowed(const GURL& url) {
   // Allow bindings for all packaged extensions and component hosted apps.
-  const Extension* extension = extensions_.GetExtensionOrAppByURL(
-      ExtensionURLInfo(url));
+  const Extension* extension = extensions_.GetExtensionOrAppByURL(url);
   return extension && (!extension->is_hosted_app() ||
                        extension->location() == Manifest::COMPONENT);
 }
 
 bool ExtensionService::ShouldBlockUrlInBrowserTab(GURL* url) {
-  const Extension* extension = extensions_.GetExtensionOrAppByURL(
-      ExtensionURLInfo(*url));
+  const Extension* extension = extensions_.GetExtensionOrAppByURL(*url);
   if (extension && extension->is_platform_app()) {
     *url = GURL(chrome::kExtensionInvalidRequestURL);
     return true;
diff --git a/chrome/browser/extensions/extension_service_unittest.cc b/chrome/browser/extensions/extension_service_unittest.cc
index 8811e48..580e728 100644
--- a/chrome/browser/extensions/extension_service_unittest.cc
+++ b/chrome/browser/extensions/extension_service_unittest.cc
@@ -20,7 +20,7 @@
 #include "base/json/json_string_value_serializer.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "base/path_service.h"
 #include "base/stl_util.h"
 #include "base/strings/string16.h"
@@ -47,6 +47,9 @@
 #include "chrome/browser/extensions/external_pref_loader.h"
 #include "chrome/browser/extensions/external_provider_impl.h"
 #include "chrome/browser/extensions/external_provider_interface.h"
+#include "chrome/browser/extensions/install_observer.h"
+#include "chrome/browser/extensions/install_tracker.h"
+#include "chrome/browser/extensions/install_tracker_factory.h"
 #include "chrome/browser/extensions/installed_loader.h"
 #include "chrome/browser/extensions/management_policy.h"
 #include "chrome/browser/extensions/pack_extension_job.h"
@@ -110,7 +113,6 @@
 #include "webkit/browser/database/database_tracker.h"
 #include "webkit/browser/quota/quota_manager.h"
 #include "webkit/common/database/database_identifier.h"
-#include "webkit/plugins/npapi/mock_plugin_list.h"
 
 #if defined(OS_CHROMEOS)
 #include "chrome/browser/chromeos/extensions/install_limiter.h"
@@ -441,7 +443,6 @@
       expected_extensions_count_(0),
       ui_thread_(BrowserThread::UI, &loop_),
       db_thread_(BrowserThread::DB, &loop_),
-      webkit_thread_(BrowserThread::WEBKIT_DEPRECATED, &loop_),
       file_thread_(BrowserThread::FILE, &loop_),
       file_user_blocking_thread_(BrowserThread::FILE_USER_BLOCKING, &loop_),
       io_thread_(BrowserThread::IO, &loop_) {
@@ -468,12 +469,18 @@
   TestingProfile::Builder profile_builder;
   // Create a PrefService that only contains user defined preference values.
   PrefServiceMockBuilder builder;
-  builder.WithUserFilePrefs(params.pref_file, loop_.message_loop_proxy().get());
-  scoped_refptr<user_prefs::PrefRegistrySyncable> registry(
-      new user_prefs::PrefRegistrySyncable);
-  scoped_ptr<PrefServiceSyncable> prefs(builder.CreateSyncable(registry.get()));
-  chrome::RegisterUserProfilePrefs(registry.get());
-  profile_builder.SetPrefService(prefs.Pass());
+  // If pref_file is empty, TestingProfile automatically creates
+  // TestingPrefServiceSyncable instance.
+  if (!params.pref_file.empty()) {
+    builder.WithUserFilePrefs(params.pref_file,
+                              loop_.message_loop_proxy().get());
+    scoped_refptr<user_prefs::PrefRegistrySyncable> registry(
+        new user_prefs::PrefRegistrySyncable);
+    scoped_ptr<PrefServiceSyncable> prefs(
+        builder.CreateSyncable(registry.get()));
+    chrome::RegisterUserProfilePrefs(registry.get());
+    profile_builder.SetPrefService(prefs.Pass());
+  }
   profile_builder.SetPath(params.profile_path);
   profile_ = profile_builder.Build();
 
@@ -1608,6 +1615,80 @@
   // TODO(erikkay): add tests for upgrade cases.
 }
 
+struct MockInstallObserver : public extensions::InstallObserver {
+  MockInstallObserver() {
+  }
+
+  virtual ~MockInstallObserver() {
+  }
+
+  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 OnExtensionInstalled(const Extension* extension) OVERRIDE {
+    last_extension_installed = extension->id();
+  }
+
+  virtual void OnInstallFailure(const std::string& extension_id) OVERRIDE {
+  }
+
+  virtual void OnExtensionLoaded(const Extension* extension) OVERRIDE {
+  }
+
+  virtual void OnExtensionUnloaded(const Extension* extension) OVERRIDE {
+  }
+
+  virtual void OnExtensionUninstalled(const Extension* extension) OVERRIDE {
+    last_extension_uninstalled = extension->id();
+  }
+
+  virtual void OnAppsReordered() OVERRIDE {
+  }
+
+  virtual void OnAppInstalledToAppList(
+      const std::string& extension_id) OVERRIDE {
+  }
+
+  virtual void OnShutdown() OVERRIDE {
+  }
+
+  std::string last_extension_installed;
+  std::string last_extension_uninstalled;
+};
+
+// Test that correct notifications are sent to InstallTracker observers on
+// extension install and uninstall.
+TEST_F(ExtensionServiceTest, InstallObserverNotified) {
+  InitializeEmptyExtensionService();
+
+  extensions::InstallTracker* tracker(
+      extensions::InstallTrackerFactory::GetForProfile(profile_.get()));
+  MockInstallObserver observer;
+  tracker->AddObserver(&observer);
+
+  // A simple extension that should install without error.
+  ASSERT_TRUE(observer.last_extension_installed.empty());
+  base::FilePath path = data_dir_.AppendASCII("good.crx");
+  InstallCRX(path, INSTALL_NEW);
+  ASSERT_EQ(good_crx, observer.last_extension_installed);
+
+  // Uninstall the extension.
+  ASSERT_TRUE(observer.last_extension_uninstalled.empty());
+  UninstallExtension(good_crx, false);
+  ASSERT_EQ(good_crx, observer.last_extension_uninstalled);
+
+  tracker->RemoveObserver(&observer);
+}
+
 // Tests that flags passed to OnExternalExtensionFileFound() make it to the
 // extension object.
 TEST_F(ExtensionServiceTest, InstallingExternalExtensionWithFlags) {
@@ -2911,6 +2992,7 @@
   EXPECT_EQ(0u, service_->disabled_extensions()->size());
 
   // But the extension with no plugin should since there's no prompt.
+  ExtensionErrorReporter::GetInstance()->ClearErrors();
   extensions::UnpackedInstaller::Create(service_)->Load(
       extension_no_plugin_path);
   loop_.RunUntilIdle();
@@ -2925,6 +3007,7 @@
       switches::kAppsGalleryInstallAutoConfirmForTests,
       "accept");
 
+  ExtensionErrorReporter::GetInstance()->ClearErrors();
   extensions::UnpackedInstaller::Create(service_)->Load(
       extension_with_plugin_path);
   loop_.RunUntilIdle();
@@ -4844,6 +4927,10 @@
 TEST(ExtensionServiceTestSimple, Enabledness) {
   // Make sure the PluginService singleton is destroyed at the end of the test.
   base::ShadowingAtExitManager at_exit_manager;
+#if defined(ENABLE_PLUGINS)
+  content::PluginService::GetInstance()->Init();
+  content::PluginService::GetInstance()->DisablePluginsDiscoveryForTesting();
+#endif
 
   ExtensionErrorReporter::Init(false);  // no noisy errors
   ExtensionsReadyRecorder recorder;
@@ -4861,11 +4948,6 @@
   base::FilePath install_dir = profile->GetPath()
       .AppendASCII(extensions::kInstallDirectoryName);
 
-#if defined(ENABLE_PLUGINS)
-  webkit::npapi::MockPluginList plugin_list;
-  PluginService::GetInstance()->SetPluginListForTesting(&plugin_list);
-#endif
-
   // By default, we are enabled.
   command_line.reset(new CommandLine(CommandLine::NO_PROGRAM));
   ExtensionService* service = static_cast<extensions::TestExtensionSystem*>(
@@ -4931,13 +5013,6 @@
   service = NULL;
   // Execute any pending deletion tasks.
   loop.RunUntilIdle();
-
-#if defined(ENABLE_PLUGINS)
-  // Ensure that even if the PluginService is re-used for a later test, it
-  // won't still hold a reference to the stack position of our MockPluginList.
-  // See crbug.com/159754.
-  PluginService::GetInstance()->SetPluginListForTesting(NULL);
-#endif
 }
 
 // Test loading extensions that require limited and unlimited storage quotas.
diff --git a/chrome/browser/extensions/extension_service_unittest.h b/chrome/browser/extensions/extension_service_unittest.h
index e6d70c8..24be033 100644
--- a/chrome/browser/extensions/extension_service_unittest.h
+++ b/chrome/browser/extensions/extension_service_unittest.h
@@ -10,7 +10,7 @@
 #include "base/files/scoped_temp_dir.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/common/extensions/feature_switch.h"
 #include "content/public/test/test_browser_thread.h"
@@ -82,7 +82,6 @@
   size_t expected_extensions_count_;
   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_;
diff --git a/chrome/browser/extensions/extension_special_storage_policy_unittest.cc b/chrome/browser/extensions/extension_special_storage_policy_unittest.cc
index 7e07052..74f34fe 100644
--- a/chrome/browser/extensions/extension_special_storage_policy_unittest.cc
+++ b/chrome/browser/extensions/extension_special_storage_policy_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "base/values.h"
 #include "chrome/browser/content_settings/cookie_settings.h"
 #include "chrome/browser/extensions/extension_special_storage_policy.h"
diff --git a/chrome/browser/extensions/extension_ui_unittest.cc b/chrome/browser/extensions/extension_ui_unittest.cc
index 0ebcde7..8581038 100644
--- a/chrome/browser/extensions/extension_ui_unittest.cc
+++ b/chrome/browser/extensions/extension_ui_unittest.cc
@@ -4,7 +4,7 @@
 
 #include "base/command_line.h"
 #include "base/json/json_file_value_serializer.h"
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "base/path_service.h"
 #include "base/strings/string_util.h"
 #include "chrome/browser/extensions/extension_service.h"
diff --git a/chrome/browser/extensions/extension_uninstall_dialog.cc b/chrome/browser/extensions/extension_uninstall_dialog.cc
index e91fbff..0eb8dcf 100644
--- a/chrome/browser/extensions/extension_uninstall_dialog.cc
+++ b/chrome/browser/extensions/extension_uninstall_dialog.cc
@@ -6,7 +6,7 @@
 
 #include "base/bind.h"
 #include "base/logging.h"
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/extensions/image_loader.h"
 #include "chrome/browser/ui/browser.h"
diff --git a/chrome/browser/extensions/extension_web_ui.cc b/chrome/browser/extensions/extension_web_ui.cc
index 3ea194b..40a4deb 100644
--- a/chrome/browser/extensions/extension_web_ui.cc
+++ b/chrome/browser/extensions/extension_web_ui.cc
@@ -129,7 +129,7 @@
   Profile* profile = Profile::FromWebUI(web_ui);
   ExtensionService* service = profile->GetExtensionService();
   const Extension* extension =
-      service->extensions()->GetExtensionOrAppByURL(ExtensionURLInfo(url));
+      service->extensions()->GetExtensionOrAppByURL(url);
   DCHECK(extension);
 
   // The base class defaults to enabling WebUI bindings, but we don't need
diff --git a/chrome/browser/extensions/extensions_quota_service.cc b/chrome/browser/extensions/extensions_quota_service.cc
index f776c40..830c93a 100644
--- a/chrome/browser/extensions/extensions_quota_service.cc
+++ b/chrome/browser/extensions/extensions_quota_service.cc
@@ -4,7 +4,7 @@
 
 #include "chrome/browser/extensions/extensions_quota_service.h"
 
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "base/stl_util.h"
 #include "chrome/browser/extensions/extension_function.h"
 #include "extensions/common/error_utils.h"
diff --git a/chrome/browser/extensions/extensions_quota_service_unittest.cc b/chrome/browser/extensions/extensions_quota_service_unittest.cc
index 4ebbf5a..9cb6fdc 100644
--- a/chrome/browser/extensions/extensions_quota_service_unittest.cc
+++ b/chrome/browser/extensions/extensions_quota_service_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "base/process.h"
 #include "base/stl_util.h"
 #include "base/strings/string_util.h"
diff --git a/chrome/browser/extensions/external_install_ui.cc b/chrome/browser/extensions/external_install_ui.cc
index fe7fc25..0888c97 100644
--- a/chrome/browser/extensions/external_install_ui.cc
+++ b/chrome/browser/extensions/external_install_ui.cc
@@ -10,7 +10,7 @@
 #include "base/lazy_instance.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "base/metrics/histogram.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/app/chrome_command_ids.h"
diff --git a/chrome/browser/extensions/external_policy_loader_unittest.cc b/chrome/browser/extensions/external_policy_loader_unittest.cc
index f8e0340..4270a24 100644
--- a/chrome/browser/extensions/external_policy_loader_unittest.cc
+++ b/chrome/browser/extensions/external_policy_loader_unittest.cc
@@ -6,7 +6,7 @@
 #include <string>
 
 #include "base/logging.h"
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "base/values.h"
 #include "base/version.h"
 #include "chrome/browser/extensions/external_policy_loader.h"
diff --git a/chrome/browser/extensions/image_loader_unittest.cc b/chrome/browser/extensions/image_loader_unittest.cc
index 4d50f6b..8c541a6 100644
--- a/chrome/browser/extensions/image_loader_unittest.cc
+++ b/chrome/browser/extensions/image_loader_unittest.cc
@@ -5,7 +5,7 @@
 #include "chrome/browser/extensions/image_loader.h"
 
 #include "base/json/json_file_value_serializer.h"
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "base/path_service.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/common/chrome_paths.h"
diff --git a/chrome/browser/extensions/menu_manager_unittest.cc b/chrome/browser/extensions/menu_manager_unittest.cc
index 40dfeed..e8ad2c6 100644
--- a/chrome/browser/extensions/menu_manager_unittest.cc
+++ b/chrome/browser/extensions/menu_manager_unittest.cc
@@ -7,7 +7,7 @@
 #include "base/files/scoped_temp_dir.h"
 #include "base/json/json_reader.h"
 #include "base/memory/scoped_vector.h"
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "base/path_service.h"
 #include "base/prefs/pref_service.h"
 #include "base/strings/utf_string_conversions.h"
diff --git a/chrome/browser/extensions/navigation_observer.cc b/chrome/browser/extensions/navigation_observer.cc
index f8030e9..3e3bde3 100644
--- a/chrome/browser/extensions/navigation_observer.cc
+++ b/chrome/browser/extensions/navigation_observer.cc
@@ -59,7 +59,7 @@
   ExtensionService* extension_service =
       extensions::ExtensionSystem::Get(profile_)->extension_service();
   const Extension* extension = extension_service->disabled_extensions()->
-      GetExtensionOrAppByURL(ExtensionURLInfo(nav_entry->GetURL()));
+      GetExtensionOrAppByURL(nav_entry->GetURL());
   if (!extension)
     return;
 
diff --git a/chrome/browser/extensions/pack_extension_job.cc b/chrome/browser/extensions/pack_extension_job.cc
index 1af8399..744eb62 100644
--- a/chrome/browser/extensions/pack_extension_job.cc
+++ b/chrome/browser/extensions/pack_extension_job.cc
@@ -5,7 +5,7 @@
 #include "chrome/browser/extensions/pack_extension_job.h"
 
 #include "base/bind.h"
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/extensions/extension_creator.h"
diff --git a/chrome/browser/extensions/pack_extension_unittest.cc b/chrome/browser/extensions/pack_extension_unittest.cc
index dddfe4d..dac4608 100644
--- a/chrome/browser/extensions/pack_extension_unittest.cc
+++ b/chrome/browser/extensions/pack_extension_unittest.cc
@@ -6,7 +6,7 @@
 #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/message_loop.h"
 #include "base/path_service.h"
 #include "chrome/browser/extensions/startup_helper.h"
 #include "chrome/common/chrome_paths.h"
diff --git a/chrome/browser/extensions/page_action_browsertest.cc b/chrome/browser/extensions/page_action_browsertest.cc
index 90e8ef7..52a0dd4 100644
--- a/chrome/browser/extensions/page_action_browsertest.cc
+++ b/chrome/browser/extensions/page_action_browsertest.cc
@@ -11,9 +11,9 @@
 #include "chrome/browser/extensions/extension_tab_util.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "chrome/common/chrome_switches.h"
 #include "chrome/common/extensions/extension.h"
 #include "chrome/test/base/ui_test_utils.h"
+#include "extensions/common/switches.h"
 
 namespace extensions {
 namespace {
diff --git a/chrome/browser/extensions/page_action_controller_unittest.cc b/chrome/browser/extensions/page_action_controller_unittest.cc
index 70358eb..ed35108 100644
--- a/chrome/browser/extensions/page_action_controller_unittest.cc
+++ b/chrome/browser/extensions/page_action_controller_unittest.cc
@@ -6,7 +6,7 @@
 
 #include "base/command_line.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "chrome/browser/extensions/extension_action.h"
 #include "chrome/browser/extensions/extension_action_manager.h"
 #include "chrome/browser/extensions/extension_service.h"
diff --git a/chrome/browser/extensions/platform_app_browsertest.cc b/chrome/browser/extensions/platform_app_browsertest.cc
index e301d3d..d193507 100644
--- a/chrome/browser/extensions/platform_app_browsertest.cc
+++ b/chrome/browser/extensions/platform_app_browsertest.cc
@@ -45,6 +45,10 @@
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "url/gurl.h"
 
+#if defined(OS_WIN) && defined(USE_ASH)
+#include "base/win/windows_version.h"
+#endif
+
 using apps::ShellWindow;
 using content::WebContents;
 using web_modal::WebContentsModalDialogManager;
@@ -792,6 +796,11 @@
 #define MAYBE_ReOpenedWithID ReOpenedWithID
 #endif
 IN_PROC_BROWSER_TEST_F(PlatformAppDevToolsBrowserTest, MAYBE_ReOpenedWithID) {
+#if defined(OS_WIN) && defined(USE_ASH)
+  // Disable this test in Metro+Ash for now (http://crbug.com/179830).
+  if (base::win::GetVersion() >= base::win::VERSION_WIN8)
+    return;
+#endif
   RunTestWithDevTools("minimal_id", RELAUNCH | HAS_ID);
 }
 
@@ -950,19 +959,12 @@
   extensions::ExtensionSystem::Get(browser()->profile())->event_router()->
       SetRegisteredEvents(extension->id(), std::set<std::string>());
 
-  const base::StringValue old_version("1");
-  std::string pref_path("extensions.settings.");
-  pref_path += extension->id();
-  pref_path += ".manifest.version";
-  // TODO(joi): Do registrations up front.
-  user_prefs::PrefRegistrySyncable* registry =
-      static_cast<user_prefs::PrefRegistrySyncable*>(
-          extension_prefs->pref_service()->DeprecatedGetPrefRegistry());
-  registry->RegisterStringPref(
-      pref_path.c_str(),
-      std::string(),
-      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
-  extension_prefs->pref_service()->Set(pref_path.c_str(), old_version);
+  DictionaryPrefUpdate update(extension_prefs->pref_service(),
+                              ExtensionPrefs::kExtensionsPref);
+  DictionaryValue* dict = update.Get();
+  std::string key(extension->id());
+  key += ".manifest.version";
+  dict->SetString(key, "1");
 }
 
 // Component App Test 3 of 3: simulate a component extension upgrade that
diff --git a/chrome/browser/extensions/plugin_apitest.cc b/chrome/browser/extensions/plugin_apitest.cc
index 39b1118..16d5ed9 100644
--- a/chrome/browser/extensions/plugin_apitest.cc
+++ b/chrome/browser/extensions/plugin_apitest.cc
@@ -15,10 +15,14 @@
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "content/public/browser/navigation_controller.h"
+#include "content/public/browser/plugin_service.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/browser_test_utils.h"
 #include "net/base/net_util.h"
-#include "webkit/plugins/npapi/plugin_utils.h"
+
+#if defined(OS_WIN) && defined(USE_ASH)
+#include "base/win/windows_version.h"
+#endif
 
 using content::NavigationController;
 using content::WebContents;
@@ -41,7 +45,7 @@
 // Tests that a renderer's plugin list is properly updated when we load and
 // unload an extension that contains a plugin.
 IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, MAYBE_PluginLoadUnload) {
-  if (!webkit::npapi::NPAPIPluginsSupported())
+  if (!content::PluginService::GetInstance()->NPAPIPluginsSupported())
     return;
   browser()->profile()->GetPrefs()->SetBoolean(prefs::kPluginsAlwaysAuthorize,
                                                true);
@@ -124,7 +128,13 @@
 #endif
 // Tests that private extension plugins are only visible to the extension.
 IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, MAYBE_PluginPrivate) {
-  if (!webkit::npapi::NPAPIPluginsSupported())
+#if defined(OS_WIN) && defined(USE_ASH)
+  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
+  if (base::win::GetVersion() >= base::win::VERSION_WIN8)
+    return;
+#endif
+
+  if (!content::PluginService::GetInstance()->NPAPIPluginsSupported())
     return;
 
   browser()->profile()->GetPrefs()->SetBoolean(prefs::kPluginsAlwaysAuthorize,
diff --git a/chrome/browser/extensions/plugin_manager.cc b/chrome/browser/extensions/plugin_manager.cc
index f797cda..ff77620 100644
--- a/chrome/browser/extensions/plugin_manager.cc
+++ b/chrome/browser/extensions/plugin_manager.cc
@@ -148,7 +148,7 @@
   if (!pepper_info)
     return;
 
-  std::vector<webkit::WebPluginMimeType>::const_iterator mime_iter;
+  std::vector<content::WebPluginMimeType>::const_iterator mime_iter;
   // Check each MIME type the plugins handle for the NaCl MIME type.
   for (mime_iter = pepper_info->mime_types.begin();
        mime_iter != pepper_info->mime_types.end(); ++mime_iter) {
@@ -157,7 +157,7 @@
 
       PluginService::GetInstance()->UnregisterInternalPlugin(pepper_info->path);
 
-      webkit::WebPluginInfo info = pepper_info->ToWebPluginInfo();
+      content::WebPluginInfo info = pepper_info->ToWebPluginInfo();
 
       for (NaClModuleInfo::List::const_iterator iter =
                nacl_module_list_.begin();
@@ -165,7 +165,7 @@
         // Add the MIME type specified in the extension to this NaCl plugin,
         // With an extra "nacl" argument to specify the location of the NaCl
         // manifest file.
-        webkit::WebPluginMimeType mime_type_info;
+        content::WebPluginMimeType mime_type_info;
         mime_type_info.mime_type = iter->mime_type;
         mime_type_info.additional_param_names.push_back(UTF8ToUTF16("nacl"));
         mime_type_info.additional_param_values.push_back(
diff --git a/chrome/browser/extensions/requirements_checker_browsertest.cc b/chrome/browser/extensions/requirements_checker_browsertest.cc
index 337c31f..30b01d6 100644
--- a/chrome/browser/extensions/requirements_checker_browsertest.cc
+++ b/chrome/browser/extensions/requirements_checker_browsertest.cc
@@ -8,7 +8,7 @@
 #include "base/command_line.h"
 #include "base/files/file_path.h"
 #include "base/memory/ref_counted.h"
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "base/path_service.h"
 #include "base/strings/string_util.h"
 #include "base/threading/sequenced_worker_pool.h"
diff --git a/chrome/browser/extensions/sandboxed_unpacker.cc b/chrome/browser/extensions/sandboxed_unpacker.cc
index cb40deb..e2b317f 100644
--- a/chrome/browser/extensions/sandboxed_unpacker.cc
+++ b/chrome/browser/extensions/sandboxed_unpacker.cc
@@ -13,7 +13,7 @@
 #include "base/files/file_util_proxy.h"
 #include "base/json/json_string_value_serializer.h"
 #include "base/memory/scoped_handle.h"
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "base/metrics/histogram.h"
 #include "base/path_service.h"
 #include "base/sequenced_task_runner.h"
diff --git a/chrome/browser/extensions/sandboxed_unpacker_unittest.cc b/chrome/browser/extensions/sandboxed_unpacker_unittest.cc
index 55fe555..1bf0018 100644
--- a/chrome/browser/extensions/sandboxed_unpacker_unittest.cc
+++ b/chrome/browser/extensions/sandboxed_unpacker_unittest.cc
@@ -5,7 +5,7 @@
 #include "base/bind.h"
 #include "base/file_util.h"
 #include "base/memory/ref_counted.h"
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "base/path_service.h"
 #include "base/run_loop.h"
 #include "base/strings/string_util.h"
diff --git a/chrome/browser/extensions/script_badge_controller_unittest.cc b/chrome/browser/extensions/script_badge_controller_unittest.cc
index 6eed1ad..9b0eddc 100644
--- a/chrome/browser/extensions/script_badge_controller_unittest.cc
+++ b/chrome/browser/extensions/script_badge_controller_unittest.cc
@@ -6,7 +6,7 @@
 
 #include "base/command_line.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "base/strings/stringprintf.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/extensions/extension_action_manager.h"
diff --git a/chrome/browser/extensions/script_bubble_controller_unittest.cc b/chrome/browser/extensions/script_bubble_controller_unittest.cc
index 8f7a269..cce310c 100644
--- a/chrome/browser/extensions/script_bubble_controller_unittest.cc
+++ b/chrome/browser/extensions/script_bubble_controller_unittest.cc
@@ -7,7 +7,7 @@
 #include "base/command_line.h"
 #include "base/files/file_path.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "chrome/browser/extensions/component_loader.h"
 #include "chrome/browser/extensions/extension_action.h"
 #include "chrome/browser/extensions/extension_action_manager.h"
diff --git a/chrome/browser/extensions/script_executor.h b/chrome/browser/extensions/script_executor.h
index 7bfbf79..d463bf0 100644
--- a/chrome/browser/extensions/script_executor.h
+++ b/chrome/browser/extensions/script_executor.h
@@ -10,7 +10,7 @@
 #include "base/callback_forward.h"
 #include "base/observer_list.h"
 #include "chrome/browser/extensions/tab_helper.h"
-#include "chrome/common/extensions/user_script.h"
+#include "extensions/common/user_script.h"
 
 class GURL;
 
diff --git a/chrome/browser/extensions/standard_management_policy_provider_unittest.cc b/chrome/browser/extensions/standard_management_policy_provider_unittest.cc
index d4f9605..ae6f6e5 100644
--- a/chrome/browser/extensions/standard_management_policy_provider_unittest.cc
+++ b/chrome/browser/extensions/standard_management_policy_provider_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/values.h"
 #include "chrome/browser/extensions/blacklist.h"
diff --git a/chrome/browser/extensions/startup_helper.cc b/chrome/browser/extensions/startup_helper.cc
index 7bc9524..09f45f3 100644
--- a/chrome/browser/extensions/startup_helper.cc
+++ b/chrome/browser/extensions/startup_helper.cc
@@ -8,7 +8,7 @@
 #include "base/bind_helpers.h"
 #include "base/command_line.h"
 #include "base/files/file_path.h"
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
diff --git a/chrome/browser/extensions/state_store.cc b/chrome/browser/extensions/state_store.cc
index c89cfc3..0169ee5 100644
--- a/chrome/browser/extensions/state_store.cc
+++ b/chrome/browser/extensions/state_store.cc
@@ -5,7 +5,7 @@
 #include "chrome/browser/extensions/state_store.h"
 
 #include "base/bind.h"
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/common/extensions/extension.h"
 #include "content/public/browser/notification_service.h"
diff --git a/chrome/browser/extensions/tab_helper.cc b/chrome/browser/extensions/tab_helper.cc
index cfd07b7..ac7620c 100644
--- a/chrome/browser/extensions/tab_helper.cc
+++ b/chrome/browser/extensions/tab_helper.cc
@@ -311,11 +311,10 @@
   const ExtensionSet* extensions = extension_service->extensions();
   const ExtensionSet* disabled = extension_service->disabled_extensions();
 
-  ExtensionURLInfo url(requestor_url);
   std::string state;
-  if (extensions->GetHostedAppByURL(url))
+  if (extensions->GetHostedAppByURL(requestor_url))
     state = extension_misc::kAppStateInstalled;
-  else if (disabled->GetHostedAppByURL(url))
+  else if (disabled->GetHostedAppByURL(requestor_url))
     state = extension_misc::kAppStateDisabled;
   else
     state = extension_misc::kAppStateNotInstalled;
diff --git a/chrome/browser/extensions/test_blacklist.cc b/chrome/browser/extensions/test_blacklist.cc
index 249d929..77b75b2 100644
--- a/chrome/browser/extensions/test_blacklist.cc
+++ b/chrome/browser/extensions/test_blacklist.cc
@@ -7,7 +7,7 @@
 #include <set>
 
 #include "base/bind.h"
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "chrome/browser/extensions/blacklist.h"
 
diff --git a/chrome/browser/extensions/test_extension_environment.h b/chrome/browser/extensions/test_extension_environment.h
index a193345..904f961 100644
--- a/chrome/browser/extensions/test_extension_environment.h
+++ b/chrome/browser/extensions/test_extension_environment.h
@@ -6,7 +6,7 @@
 #define CHROME_BROWSER_EXTENSIONS_TEST_EXTENSION_ENVIRONMENT_H_
 
 #include "base/memory/scoped_ptr.h"
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "content/public/test/test_browser_thread.h"
 
 #if defined(OS_CHROMEOS)
diff --git a/chrome/browser/extensions/test_extension_prefs.cc b/chrome/browser/extensions/test_extension_prefs.cc
index 6c21f20..e2d8a70 100644
--- a/chrome/browser/extensions/test_extension_prefs.cc
+++ b/chrome/browser/extensions/test_extension_prefs.cc
@@ -8,7 +8,7 @@
 #include "base/bind_helpers.h"
 #include "base/file_util.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "base/message_loop/message_loop_proxy.h"
 #include "base/prefs/json_pref_store.h"
 #include "base/prefs/pref_value_store.h"
diff --git a/chrome/browser/extensions/theme_installed_infobar_delegate.cc b/chrome/browser/extensions/theme_installed_infobar_delegate.cc
index 3a0ae75..be6ede8 100644
--- a/chrome/browser/extensions/theme_installed_infobar_delegate.cc
+++ b/chrome/browser/extensions/theme_installed_infobar_delegate.cc
@@ -54,15 +54,15 @@
   // If there's a previous theme infobar, just replace that instead of adding a
   // new one.
   for (size_t i = 0; i < infobar_service->infobar_count(); ++i) {
-    InfoBarDelegate* delegate = infobar_service->infobar_at(i);
+    InfoBarDelegate* old_infobar = infobar_service->infobar_at(i);
     ThemeInstalledInfoBarDelegate* theme_infobar =
-        delegate->AsThemePreviewInfobarDelegate();
+        old_infobar->AsThemePreviewInfobarDelegate();
     if (theme_infobar) {
       // If the user installed the same theme twice, ignore the second install
       // and keep the first install info bar, so that they can easily undo to
       // get back the previous theme.
       if (theme_infobar->theme_id_ != new_theme->id()) {
-        infobar_service->ReplaceInfoBar(delegate, new_infobar.Pass());
+        infobar_service->ReplaceInfoBar(old_infobar, new_infobar.Pass());
         theme_service->OnInfobarDisplayed();
       }
       return;
@@ -135,7 +135,7 @@
         extension_service_->GetExtensionById(previous_theme_id_, true);
     if (previous_theme) {
       theme_service_->SetTheme(previous_theme);
-        return false;  // The theme change will close us.
+      return false;  // The theme change will close us.
     }
   }
 
diff --git a/chrome/browser/extensions/theme_installed_infobar_delegate.h b/chrome/browser/extensions/theme_installed_infobar_delegate.h
index 14ba85d..f37efcc 100644
--- a/chrome/browser/extensions/theme_installed_infobar_delegate.h
+++ b/chrome/browser/extensions/theme_installed_infobar_delegate.h
@@ -26,8 +26,8 @@
 class ThemeInstalledInfoBarDelegate : public ConfirmInfoBarDelegate,
                                       public content::NotificationObserver {
  public:
-  // Creates a theme installed delegate and adds it to the last active tab on
-  // |profile|.
+  // Creates a theme installed infobar delegate and adds it to the last active
+  // tab on |profile|.
   static void Create(const extensions::Extension* new_theme,
                      Profile* profile,
                      const std::string& previous_theme_id,
diff --git a/chrome/browser/extensions/updater/extension_updater_unittest.cc b/chrome/browser/extensions/updater/extension_updater_unittest.cc
index 07599e1..8fdd4bf 100644
--- a/chrome/browser/extensions/updater/extension_updater_unittest.cc
+++ b/chrome/browser/extensions/updater/extension_updater_unittest.cc
@@ -13,7 +13,7 @@
 #include "base/compiler_specific.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/sequenced_task_runner.h"
 #include "base/stl_util.h"
diff --git a/chrome/browser/extensions/updater/request_queue_impl.h b/chrome/browser/extensions/updater/request_queue_impl.h
index baa2d4d..db167e8 100644
--- a/chrome/browser/extensions/updater/request_queue_impl.h
+++ b/chrome/browser/extensions/updater/request_queue_impl.h
@@ -9,7 +9,7 @@
 
 #include "base/bind.h"
 #include "base/compiler_specific.h"
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "base/stl_util.h"
 #include "chrome/browser/extensions/updater/request_queue.h"
 
diff --git a/chrome/browser/extensions/user_script_listener.h b/chrome/browser/extensions/user_script_listener.h
index d4f6c4a..009a9d7 100644
--- a/chrome/browser/extensions/user_script_listener.h
+++ b/chrome/browser/extensions/user_script_listener.h
@@ -15,7 +15,7 @@
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
-#include "webkit/glue/resource_type.h"
+#include "webkit/common/resource_type.h"
 
 class GURL;
 class URLPattern;
diff --git a/chrome/browser/extensions/user_script_listener_unittest.cc b/chrome/browser/extensions/user_script_listener_unittest.cc
index 23ea469..1f5dc67 100644
--- a/chrome/browser/extensions/user_script_listener_unittest.cc
+++ b/chrome/browser/extensions/user_script_listener_unittest.cc
@@ -4,7 +4,7 @@
 
 #include "base/file_util.h"
 #include "base/json/json_file_value_serializer.h"
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "base/threading/thread.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/extensions/extension_service_unittest.h"
diff --git a/chrome/browser/extensions/user_script_master.h b/chrome/browser/extensions/user_script_master.h
index b805f7c..44aeb93 100644
--- a/chrome/browser/extensions/user_script_master.h
+++ b/chrome/browser/extensions/user_script_master.h
@@ -17,10 +17,10 @@
 #include "chrome/browser/extensions/extension_info_map.h"
 #include "chrome/common/extensions/extension_messages.h"
 #include "chrome/common/extensions/extension_set.h"
-#include "chrome/common/extensions/user_script.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
+#include "extensions/common/user_script.h"
 
 namespace content {
 class RenderProcessHost;
diff --git a/chrome/browser/extensions/user_script_master_unittest.cc b/chrome/browser/extensions/user_script_master_unittest.cc
index d072c30..dc55c56 100644
--- a/chrome/browser/extensions/user_script_master_unittest.cc
+++ b/chrome/browser/extensions/user_script_master_unittest.cc
@@ -9,7 +9,7 @@
 #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/message_loop.h"
 #include "base/path_service.h"
 #include "base/strings/string_util.h"
 #include "chrome/browser/chrome_notification_types.h"
diff --git a/chrome/browser/extensions/web_view_interactive_browsertest.cc b/chrome/browser/extensions/web_view_interactive_browsertest.cc
index 04d6e4b..95fcfb8 100644
--- a/chrome/browser/extensions/web_view_interactive_browsertest.cc
+++ b/chrome/browser/extensions/web_view_interactive_browsertest.cc
@@ -143,6 +143,12 @@
     LoadAndLaunchPlatformApp(app_location.c_str());
     ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
 
+    ASSERT_TRUE(ui_test_utils::ShowAndFocusNativeWindow(
+        GetPlatformAppWindow()));
+
+    // Flush any pending events to make sure we start with a clean slate.
+    content::RunAllPendingInMessageLoop();
+
     content::WebContents* embedder_web_contents =
         GetFirstShellWindowWebContents();
     ASSERT_TRUE(embedder_web_contents);
@@ -654,3 +660,12 @@
 
   ASSERT_TRUE(done_listener.WaitUntilSatisfied());
 }
+
+IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest,
+                       PointerLock_PointerLockLostWithFocus) {
+  TestHelper("testPointerLockLostWithFocus",
+             "DonePointerLockTest.PASSED",
+             "DonePointerLockTest.FAILED",
+             "web_view/pointerlock");
+}
+
diff --git a/chrome/browser/extensions/webstore_startup_installer_browsertest.cc b/chrome/browser/extensions/webstore_startup_installer_browsertest.cc
index 6b727f4..1ff011b 100644
--- a/chrome/browser/extensions/webstore_startup_installer_browsertest.cc
+++ b/chrome/browser/extensions/webstore_startup_installer_browsertest.cc
@@ -33,6 +33,10 @@
 #include "net/dns/mock_host_resolver.h"
 #include "url/gurl.h"
 
+#if defined(OS_WIN) && defined(USE_ASH)
+#include "base/win/windows_version.h"
+#endif
+
 using content::WebContents;
 using extensions::DictionaryBuilder;
 using extensions::Extension;
@@ -236,6 +240,12 @@
 
 IN_PROC_BROWSER_TEST_F(WebstoreStartupInstallerTest,
                        InstallProhibitedForManagedUsers) {
+#if defined(OS_WIN) && defined(USE_ASH)
+  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
+  if (base::win::GetVersion() >= base::win::VERSION_WIN8)
+    return;
+#endif
+
   CommandLine::ForCurrentProcess()->AppendSwitchASCII(
       switches::kAppsGalleryInstallAutoConfirmForTests, "accept");
 
diff --git a/chrome/browser/extensions/window_open_apitest.cc b/chrome/browser/extensions/window_open_apitest.cc
index 840ff58..1563afb 100644
--- a/chrome/browser/extensions/window_open_apitest.cc
+++ b/chrome/browser/extensions/window_open_apitest.cc
@@ -29,6 +29,10 @@
 #include "chrome/browser/extensions/shell_window_registry.h"
 #endif
 
+#if defined(OS_WIN) && defined(USE_ASH)
+#include "base/win/windows_version.h"
+#endif
+
 #if defined(USE_ASH) && !defined(OS_WIN)
 // TODO(stevenjb): Figure out the correct behavior for Ash + Win
 #define USE_ASH_PANELS
@@ -254,6 +258,12 @@
 
 IN_PROC_BROWSER_TEST_F(WindowOpenPanelTest,
                        CloseNonExtensionPanelsOnUninstall) {
+#if defined(OS_WIN) && defined(USE_ASH)
+  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
+  if (base::win::GetVersion() >= base::win::VERSION_WIN8)
+    return;
+#endif
+
 #if defined(USE_ASH_PANELS)
   // On Ash, new panel windows open as popup windows instead.
   int num_popups, num_panels;
diff --git a/chrome/browser/external_protocol/external_protocol_handler.cc b/chrome/browser/external_protocol/external_protocol_handler.cc
index 04d59e8..ac4f5f5 100644
--- a/chrome/browser/external_protocol/external_protocol_handler.cc
+++ b/chrome/browser/external_protocol/external_protocol_handler.cc
@@ -8,7 +8,7 @@
 
 #include "base/bind.h"
 #include "base/logging.h"
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "base/prefs/pref_registry_simple.h"
 #include "base/prefs/pref_service.h"
 #include "base/strings/string_util.h"
diff --git a/chrome/browser/external_protocol/external_protocol_handler_unittest.cc b/chrome/browser/external_protocol/external_protocol_handler_unittest.cc
index d8a3679..57a6db6 100644
--- a/chrome/browser/external_protocol/external_protocol_handler_unittest.cc
+++ b/chrome/browser/external_protocol/external_protocol_handler_unittest.cc
@@ -4,7 +4,7 @@
 
 #include "chrome/browser/external_protocol/external_protocol_handler.h"
 
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "content/public/test/test_browser_thread.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/chrome/browser/feedback/feedback_data.cc b/chrome/browser/feedback/feedback_data.cc
index 2e1cde3..4b4c71f 100644
--- a/chrome/browser/feedback/feedback_data.cc
+++ b/chrome/browser/feedback/feedback_data.cc
@@ -19,17 +19,11 @@
 #include "ash/shell_delegate.h"
 #endif
 
-#if defined(OS_CHROMEOS)
-#include "third_party/zlib/google/zip.h"
-#endif
-
 using content::BrowserThread;
 
 #if defined(OS_CHROMEOS)
 namespace {
 
-const char kLogsFilename[] = "system_logs.txt";
-
 const char kMultilineIndicatorString[] = "<multiline>\n";
 const char kMultilineStartString[] = "---------- START ----------\n";
 const char kMultilineEndString[] = "---------- END ----------\n\n";
@@ -57,35 +51,11 @@
   return syslogs_string;
 }
 
-bool ZipString(const std::string& logs,
-               std::string* compressed_logs) {
-  base::FilePath temp_path;
-  base::FilePath zip_file;
-
-  // Create a temporary directory, put the logs into a file in it. Create
-  // another temporary file to receive the zip file in.
-  if (!file_util::CreateNewTempDirectory("", &temp_path))
-    return false;
-  if (file_util::WriteFile(
-      temp_path.Append(kLogsFilename), logs.c_str(), logs.size()) == -1)
-    return false;
-  if (!file_util::CreateTemporaryFile(&zip_file))
-    return false;
-
-  if (!zip::Zip(temp_path, zip_file, false))
-    return false;
-
-  if (!file_util::ReadFileToString(zip_file, compressed_logs))
-    return false;
-
-  return true;
-}
-
 void ZipLogs(chromeos::SystemLogsResponse* sys_info,
              std::string* compressed_logs) {
   DCHECK(compressed_logs);
   std::string logs_string = LogsToString(sys_info);
-  if (!ZipString(logs_string, compressed_logs)) {
+  if (!FeedbackUtil::ZipString(logs_string, compressed_logs)) {
     compressed_logs->clear();
   }
 }
diff --git a/chrome/browser/feedback/feedback_util.cc b/chrome/browser/feedback/feedback_util.cc
index 7096dc9..8095fad 100644
--- a/chrome/browser/feedback/feedback_util.cc
+++ b/chrome/browser/feedback/feedback_util.cc
@@ -10,6 +10,7 @@
 
 #include "base/bind.h"
 #include "base/command_line.h"
+#include "base/file_util.h"
 #include "base/file_version_info.h"
 #include "base/memory/singleton.h"
 #include "base/message_loop/message_loop.h"
@@ -36,12 +37,20 @@
 #include "net/url_request/url_fetcher.h"
 #include "net/url_request/url_fetcher_delegate.h"
 #include "net/url_request/url_request_status.h"
-#include "third_party/icu/public/common/unicode/locid.h"
+#include "third_party/icu/source/common/unicode/locid.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "url/gurl.h"
 
+#if defined(OS_CHROMEOS)
+#include "third_party/zlib/google/zip.h"
+#endif
+
 using content::WebContents;
 
+namespace {
+const char kLogsFilename[] = "system_logs.txt";
+}
+
 namespace chrome {
 const char kAppLauncherCategoryTag[] = "AppLauncher";
 }  // namespace chrome
@@ -424,3 +433,31 @@
   gfx::Rect& screen_size = GetScreenshotSize();
   screen_size = rect;
 }
+
+#if defined(OS_CHROMEOS)
+// static
+bool FeedbackUtil::ZipString(const std::string& logs,
+                             std::string* compressed_logs) {
+  base::FilePath temp_path;
+  base::FilePath zip_file;
+
+  // Create a temporary directory, put the logs into a file in it. Create
+  // another temporary file to receive the zip file in.
+  if (!file_util::CreateNewTempDirectory("", &temp_path))
+    return false;
+  if (file_util::WriteFile(
+      temp_path.Append(kLogsFilename), logs.c_str(), logs.size()) == -1)
+    return false;
+  if (!file_util::CreateTemporaryFile(&zip_file))
+    return false;
+
+  if (!zip::Zip(temp_path, zip_file, false))
+    return false;
+
+  if (!file_util::ReadFileToString(zip_file, compressed_logs))
+    return false;
+
+  return true;
+}
+#endif // OS_CHROMEOS
+
diff --git a/chrome/browser/feedback/feedback_util.h b/chrome/browser/feedback/feedback_util.h
index 0c0cec6..163317d 100644
--- a/chrome/browser/feedback/feedback_util.h
+++ b/chrome/browser/feedback/feedback_util.h
@@ -76,6 +76,9 @@
   static void ClearScreenshotPng();
   static void SetScreenshotSize(const gfx::Rect& rect);
   static gfx::Rect& GetScreenshotSize();
+#if defined(OS_CHROMEOS)
+  static bool ZipString(const std::string& logs, std::string* compressed_logs);
+#endif
 
   class PostCleanup;
 
diff --git a/chrome/browser/first_run/first_run.cc b/chrome/browser/first_run/first_run.cc
index c5cd11f..315d6f9 100644
--- a/chrome/browser/first_run/first_run.cc
+++ b/chrome/browser/first_run/first_run.cc
@@ -11,7 +11,7 @@
 #include "base/file_util.h"
 #include "base/files/file_path.h"
 #include "base/lazy_instance.h"
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "base/metrics/histogram.h"
 #include "base/path_service.h"
 #include "base/prefs/pref_service.h"
diff --git a/chrome/browser/geolocation/OWNERS b/chrome/browser/geolocation/OWNERS
index 765d513..c2252ab 100644
--- a/chrome/browser/geolocation/OWNERS
+++ b/chrome/browser/geolocation/OWNERS
@@ -1,2 +1,6 @@
-joth@chromium.org
+# Reviews:
+# Not yet owner - mvanouwerkerk@chromium.org
 bulach@chromium.org
+
+# Just owners:
+joth@chromium.org
diff --git a/chrome/browser/geolocation/chrome_geolocation_permission_context.cc b/chrome/browser/geolocation/chrome_geolocation_permission_context.cc
index e81d950..cdf6bc4 100644
--- a/chrome/browser/geolocation/chrome_geolocation_permission_context.cc
+++ b/chrome/browser/geolocation/chrome_geolocation_permission_context.cc
@@ -24,8 +24,6 @@
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/web_contents.h"
 #include "extensions/browser/view_type_utils.h"
-#include "third_party/WebKit/public/platform/WebString.h"
-#include "third_party/WebKit/public/web/WebSecurityOrigin.h"
 
 using extensions::APIPermission;
 
@@ -71,9 +69,7 @@
   if (extension_service) {
     const extensions::Extension* extension =
         extension_service->extensions()->GetExtensionOrAppByURL(
-            ExtensionURLInfo(WebKit::WebSecurityOrigin::createFromString(
-                                 UTF8ToUTF16(requesting_frame.spec())),
-                             requesting_frame));
+            requesting_frame);
     if (IsExtensionWithPermissionOrSuggestInConsole(APIPermission::kGeolocation,
                                                     extension,
                                                     profile_)) {
diff --git a/chrome/browser/geolocation/chrome_geolocation_permission_context_unittest.cc b/chrome/browser/geolocation/chrome_geolocation_permission_context_unittest.cc
index c5f7911..10eae81 100644
--- a/chrome/browser/geolocation/chrome_geolocation_permission_context_unittest.cc
+++ b/chrome/browser/geolocation/chrome_geolocation_permission_context_unittest.cc
@@ -41,55 +41,53 @@
 using content::MockRenderProcessHost;
 
 
-// ClosedDelegateTracker ------------------------------------------------------
+// ClosedInfoBarTracker -------------------------------------------------------
 
 // We need to track which infobars were closed.
-class ClosedDelegateTracker : public content::NotificationObserver {
+class ClosedInfoBarTracker : public content::NotificationObserver {
  public:
-  ClosedDelegateTracker();
-  virtual ~ClosedDelegateTracker();
+  ClosedInfoBarTracker();
+  virtual ~ClosedInfoBarTracker();
 
   // content::NotificationObserver:
   virtual void Observe(int type,
                        const content::NotificationSource& source,
                        const content::NotificationDetails& details) OVERRIDE;
 
-  size_t size() const {
-    return removed_infobar_delegates_.size();
-  }
+  size_t size() const { return removed_infobars_.size(); }
 
-  bool Contains(InfoBarDelegate* delegate) const;
+  bool Contains(InfoBarDelegate* infobar) const;
   void Clear();
 
  private:
   FRIEND_TEST_ALL_PREFIXES(GeolocationPermissionContextTests, TabDestroyed);
   content::NotificationRegistrar registrar_;
-  std::set<InfoBarDelegate*> removed_infobar_delegates_;
+  std::set<InfoBarDelegate*> removed_infobars_;
 };
 
-ClosedDelegateTracker::ClosedDelegateTracker() {
+ClosedInfoBarTracker::ClosedInfoBarTracker() {
   registrar_.Add(this, chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED,
                  content::NotificationService::AllSources());
 }
 
-ClosedDelegateTracker::~ClosedDelegateTracker() {
+ClosedInfoBarTracker::~ClosedInfoBarTracker() {
 }
 
-void ClosedDelegateTracker::Observe(
+void ClosedInfoBarTracker::Observe(
     int type,
     const content::NotificationSource& source,
     const content::NotificationDetails& details) {
   DCHECK(type == chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED);
-  removed_infobar_delegates_.insert(
+  removed_infobars_.insert(
       content::Details<InfoBarRemovedDetails>(details)->first);
 }
 
-bool ClosedDelegateTracker::Contains(InfoBarDelegate* delegate) const {
-  return removed_infobar_delegates_.count(delegate) != 0;
+bool ClosedInfoBarTracker::Contains(InfoBarDelegate* infobar) const {
+  return removed_infobars_.count(infobar) != 0;
 }
 
-void ClosedDelegateTracker::Clear() {
-  removed_infobar_delegates_.clear();
+void ClosedInfoBarTracker::Clear() {
+  removed_infobars_.clear();
 }
 
 
@@ -130,7 +128,7 @@
 
   scoped_refptr<ChromeGeolocationPermissionContext>
       geolocation_permission_context_;
-  ClosedDelegateTracker closed_delegate_tracker_;
+  ClosedInfoBarTracker closed_infobar_tracker_;
   ScopedVector<content::WebContents> extra_tabs_;
 
   // A map between renderer child id and a pair represending the bridge id and
@@ -223,11 +221,11 @@
     ContentSetting expected_content_setting) {
   TabSpecificContentSettings* content_settings =
       TabSpecificContentSettings::FromWebContents(web_contents());
-  const GeolocationSettingsState::StateMap& state_map =
-      content_settings->geolocation_settings_state().state_map();
+  const ContentSettingsUsagesState::StateMap& state_map =
+      content_settings->geolocation_usages_state().state_map();
   EXPECT_EQ(1U, state_map.count(requesting_frame.GetOrigin()));
   EXPECT_EQ(0U, state_map.count(requesting_frame));
-  GeolocationSettingsState::StateMap::const_iterator settings =
+  ContentSettingsUsagesState::StateMap::const_iterator settings =
       state_map.find(requesting_frame.GetOrigin());
   ASSERT_FALSE(settings == state_map.end())
       << "geolocation state not found " << requesting_frame;
@@ -261,13 +259,14 @@
   EXPECT_EQ(0U, infobar_service()->infobar_count());
   RequestGeolocationPermission(RequestID(0), requesting_frame);
   ASSERT_EQ(1U, infobar_service()->infobar_count());
-  ConfirmInfoBarDelegate* infobar_0 =
+  ConfirmInfoBarDelegate* infobar_delegate =
       infobar_service()->infobar_at(0)->AsConfirmInfoBarDelegate();
-  infobar_0->Cancel();
-  infobar_service()->RemoveInfoBar(infobar_0);
-  EXPECT_EQ(1U, closed_delegate_tracker_.size());
-  EXPECT_TRUE(closed_delegate_tracker_.Contains(infobar_0));
-  delete infobar_0;
+  ASSERT_TRUE(infobar_delegate);
+  infobar_delegate->Cancel();
+  infobar_service()->RemoveInfoBar(infobar_delegate);
+  EXPECT_EQ(1U, closed_infobar_tracker_.size());
+  EXPECT_TRUE(closed_infobar_tracker_.Contains(infobar_delegate));
+  delete infobar_delegate;
 }
 
 #if defined(OS_ANDROID)
@@ -278,10 +277,10 @@
   EXPECT_EQ(0U, infobar_service()->infobar_count());
   RequestGeolocationPermission(RequestID(0), requesting_frame);
   EXPECT_EQ(1U, infobar_service()->infobar_count());
-  ConfirmInfoBarDelegate* infobar_0 =
+  ConfirmInfoBarDelegate* infobar_delegate_0 =
       infobar_service()->infobar_at(0)->AsConfirmInfoBarDelegate();
-  ASSERT_TRUE(infobar_0);
-  string16 text_0 = infobar_0->GetButtonLabel(
+  ASSERT_TRUE(infobar_delegate_0);
+  string16 text_0 = infobar_delegate_0->GetButtonLabel(
       ConfirmInfoBarDelegate::BUTTON_OK);
 
   NavigateAndCommit(requesting_frame);
@@ -289,10 +288,10 @@
   EXPECT_EQ(0U, infobar_service()->infobar_count());
   RequestGeolocationPermission(RequestID(0), requesting_frame);
   EXPECT_EQ(1U, infobar_service()->infobar_count());
-  ConfirmInfoBarDelegate* infobar_1 =
+  ConfirmInfoBarDelegate* infobar_delegate_1 =
       infobar_service()->infobar_at(0)->AsConfirmInfoBarDelegate();
-  ASSERT_TRUE(infobar_1);
-  string16 text_1 = infobar_1->GetButtonLabel(
+  ASSERT_TRUE(infobar_delegate_1);
+  string16 text_1 = infobar_delegate_1->GetButtonLabel(
       ConfirmInfoBarDelegate::BUTTON_OK);
   EXPECT_NE(text_0, text_1);
 
@@ -310,10 +309,10 @@
   EXPECT_EQ(0U, infobar_service()->infobar_count());
   RequestGeolocationPermission(RequestID(0), requesting_frame);
   EXPECT_EQ(1U, infobar_service()->infobar_count());
-  ConfirmInfoBarDelegate* infobar_0 =
+  ConfirmInfoBarDelegate* infobar_delegate =
       infobar_service()->infobar_at(0)->AsConfirmInfoBarDelegate();
-  ASSERT_TRUE(infobar_0);
-  infobar_0->Accept();
+  ASSERT_TRUE(infobar_delegate);
+  infobar_delegate->Accept();
   CheckTabContentsState(requesting_frame, CONTENT_SETTING_ALLOW);
   CheckPermissionMessageSent(0, true);
 }
@@ -325,10 +324,10 @@
   EXPECT_EQ(0U, infobar_service()->infobar_count());
   RequestGeolocationPermission(RequestID(0), requesting_frame);
   EXPECT_EQ(1U, infobar_service()->infobar_count());
-  ConfirmInfoBarDelegate* infobar_0 =
+  ConfirmInfoBarDelegate* infobar_delegate =
       infobar_service()->infobar_at(0)->AsConfirmInfoBarDelegate();
-  ASSERT_TRUE(infobar_0);
-  infobar_0->Accept();
+  ASSERT_TRUE(infobar_delegate);
+  infobar_delegate->Accept();
   EXPECT_TRUE(
       MockGoogleLocationSettingsHelper::WasGoogleLocationSettingsCalled());
 }
@@ -353,49 +352,49 @@
   RequestGeolocationPermission(RequestID(1), requesting_frame_1);
   // Ensure only one infobar is created.
   ASSERT_EQ(1U, infobar_service()->infobar_count());
-  ConfirmInfoBarDelegate* infobar_0 =
+  ConfirmInfoBarDelegate* infobar_delegate_0 =
       infobar_service()->infobar_at(0)->AsConfirmInfoBarDelegate();
-  ASSERT_TRUE(infobar_0);
-  string16 text_0 = infobar_0->GetMessageText();
+  ASSERT_TRUE(infobar_delegate_0);
+  string16 text_0 = infobar_delegate_0->GetMessageText();
 
   // Accept the first frame.
-  infobar_0->Accept();
+  infobar_delegate_0->Accept();
   CheckTabContentsState(requesting_frame_0, CONTENT_SETTING_ALLOW);
   CheckPermissionMessageSent(0, true);
 
-  infobar_service()->RemoveInfoBar(infobar_0);
-  EXPECT_EQ(1U, closed_delegate_tracker_.size());
-  EXPECT_TRUE(closed_delegate_tracker_.Contains(infobar_0));
-  closed_delegate_tracker_.Clear();
-  delete infobar_0;
+  infobar_service()->RemoveInfoBar(infobar_delegate_0);
+  EXPECT_EQ(1U, closed_infobar_tracker_.size());
+  EXPECT_TRUE(closed_infobar_tracker_.Contains(infobar_delegate_0));
+  closed_infobar_tracker_.Clear();
+  delete infobar_delegate_0;
   // Now we should have a new infobar for the second frame.
   ASSERT_EQ(1U, infobar_service()->infobar_count());
 
-  ConfirmInfoBarDelegate* infobar_1 =
+  ConfirmInfoBarDelegate* infobar_delegate_1 =
       infobar_service()->infobar_at(0)->AsConfirmInfoBarDelegate();
-  ASSERT_TRUE(infobar_1);
-  string16 text_1 = infobar_1->GetMessageText();
+  ASSERT_TRUE(infobar_delegate_1);
+  string16 text_1 = infobar_delegate_1->GetMessageText();
   EXPECT_NE(text_0, text_1);
 
   // Cancel (block) this frame.
-  infobar_1->Cancel();
+  infobar_delegate_1->Cancel();
   CheckTabContentsState(requesting_frame_1, CONTENT_SETTING_BLOCK);
   CheckPermissionMessageSent(1, false);
-  infobar_service()->RemoveInfoBar(infobar_1);
-  EXPECT_EQ(1U, closed_delegate_tracker_.size());
-  EXPECT_TRUE(closed_delegate_tracker_.Contains(infobar_1));
-  delete infobar_1;
+  infobar_service()->RemoveInfoBar(infobar_delegate_1);
+  EXPECT_EQ(1U, closed_infobar_tracker_.size());
+  EXPECT_TRUE(closed_infobar_tracker_.Contains(infobar_delegate_1));
+  delete infobar_delegate_1;
   EXPECT_EQ(0U, infobar_service()->infobar_count());
   // Ensure the persisted permissions are ok.
   EXPECT_EQ(CONTENT_SETTING_ALLOW,
-      profile()->GetHostContentSettingsMap()->GetContentSetting(
-          requesting_frame_0, requesting_frame_0,
-          CONTENT_SETTINGS_TYPE_GEOLOCATION, std::string()));
+            profile()->GetHostContentSettingsMap()->GetContentSetting(
+                requesting_frame_0, requesting_frame_0,
+                CONTENT_SETTINGS_TYPE_GEOLOCATION, std::string()));
 
   EXPECT_EQ(CONTENT_SETTING_BLOCK,
-      profile()->GetHostContentSettingsMap()->GetContentSetting(
-          requesting_frame_1, requesting_frame_0,
-          CONTENT_SETTINGS_TYPE_GEOLOCATION, std::string()));
+            profile()->GetHostContentSettingsMap()->GetContentSetting(
+                requesting_frame_1, requesting_frame_0,
+                CONTENT_SETTINGS_TYPE_GEOLOCATION, std::string()));
 }
 
 TEST_F(GeolocationPermissionContextTests, PermissionForFileScheme) {
@@ -404,15 +403,15 @@
   EXPECT_EQ(0U, infobar_service()->infobar_count());
   RequestGeolocationPermission(RequestID(0), requesting_frame);
   EXPECT_EQ(1U, infobar_service()->infobar_count());
-  ConfirmInfoBarDelegate* infobar =
+  ConfirmInfoBarDelegate* infobar_delegate =
       infobar_service()->infobar_at(0)->AsConfirmInfoBarDelegate();
-  ASSERT_TRUE(infobar);
+  ASSERT_TRUE(infobar_delegate);
   // Accept the frame
-  infobar->Accept();
+  infobar_delegate->Accept();
   CheckTabContentsState(requesting_frame, CONTENT_SETTING_ALLOW);
   CheckPermissionMessageSent(0, true);
-  infobar_service()->RemoveInfoBar(infobar);
-  delete infobar;
+  infobar_service()->RemoveInfoBar(infobar_delegate);
+  delete infobar_delegate;
 
   // Make sure the setting is not stored.
   EXPECT_EQ(CONTENT_SETTING_ASK,
@@ -443,34 +442,34 @@
   RequestGeolocationPermission(RequestID(1), requesting_frame_1);
   ASSERT_EQ(1U, infobar_service()->infobar_count());
 
-  ConfirmInfoBarDelegate* infobar_0 =
+  ConfirmInfoBarDelegate* infobar_delegate_0 =
       infobar_service()->infobar_at(0)->AsConfirmInfoBarDelegate();
-  ASSERT_TRUE(infobar_0);
-  string16 text_0 = infobar_0->GetMessageText();
+  ASSERT_TRUE(infobar_delegate_0);
+  string16 text_0 = infobar_delegate_0->GetMessageText();
 
   // Simulate the frame going away, ensure the infobar for this frame
   // is removed and the next pending infobar is created.
   CancelGeolocationPermissionRequest(RequestID(0), requesting_frame_0);
-  EXPECT_EQ(1U, closed_delegate_tracker_.size());
-  EXPECT_TRUE(closed_delegate_tracker_.Contains(infobar_0));
-  closed_delegate_tracker_.Clear();
-  delete infobar_0;
+  EXPECT_EQ(1U, closed_infobar_tracker_.size());
+  EXPECT_TRUE(closed_infobar_tracker_.Contains(infobar_delegate_0));
+  closed_infobar_tracker_.Clear();
+  delete infobar_delegate_0;
   ASSERT_EQ(1U, infobar_service()->infobar_count());
 
-  ConfirmInfoBarDelegate* infobar_1 =
+  ConfirmInfoBarDelegate* infobar_delegate_1 =
       infobar_service()->infobar_at(0)->AsConfirmInfoBarDelegate();
-  ASSERT_TRUE(infobar_1);
-  string16 text_1 = infobar_1->GetMessageText();
+  ASSERT_TRUE(infobar_delegate_1);
+  string16 text_1 = infobar_delegate_1->GetMessageText();
   EXPECT_NE(text_0, text_1);
 
   // Allow this frame.
-  infobar_1->Accept();
+  infobar_delegate_1->Accept();
   CheckTabContentsState(requesting_frame_1, CONTENT_SETTING_ALLOW);
   CheckPermissionMessageSent(1, true);
-  infobar_service()->RemoveInfoBar(infobar_1);
-  EXPECT_EQ(1U, closed_delegate_tracker_.size());
-  EXPECT_TRUE(closed_delegate_tracker_.Contains(infobar_1));
-  delete infobar_1;
+  infobar_service()->RemoveInfoBar(infobar_delegate_1);
+  EXPECT_EQ(1U, closed_infobar_tracker_.size());
+  EXPECT_TRUE(closed_infobar_tracker_.Contains(infobar_delegate_1));
+  delete infobar_delegate_1;
   EXPECT_EQ(0U, infobar_service()->infobar_count());
   // Ensure the persisted permissions are ok.
   EXPECT_EQ(CONTENT_SETTING_ASK,
@@ -515,32 +514,32 @@
       infobar_service_for_tab(1)->infobar_at(0)->AsConfirmInfoBarDelegate();
 
   // Accept the first tab.
-  ConfirmInfoBarDelegate* infobar_0 =
+  ConfirmInfoBarDelegate* infobar_delegate_0 =
       infobar_service()->infobar_at(0)->AsConfirmInfoBarDelegate();
-  ASSERT_TRUE(infobar_0);
-  infobar_0->Accept();
+  ASSERT_TRUE(infobar_delegate_0);
+  infobar_delegate_0->Accept();
   CheckPermissionMessageSent(0, true);
-  infobar_service()->RemoveInfoBar(infobar_0);
-  EXPECT_EQ(2U, closed_delegate_tracker_.size());
-  EXPECT_TRUE(closed_delegate_tracker_.Contains(infobar_0));
-  delete infobar_0;
+  infobar_service()->RemoveInfoBar(infobar_delegate_0);
+  EXPECT_EQ(2U, closed_infobar_tracker_.size());
+  EXPECT_TRUE(closed_infobar_tracker_.Contains(infobar_delegate_0));
+  delete infobar_delegate_0;
   // Now the infobar for the tab with the same origin should have gone.
   EXPECT_EQ(0U, infobar_service_for_tab(1)->infobar_count());
   CheckPermissionMessageSentForTab(1, 0, true);
-  EXPECT_TRUE(closed_delegate_tracker_.Contains(removed_infobar));
-  closed_delegate_tracker_.Clear();
+  EXPECT_TRUE(closed_infobar_tracker_.Contains(removed_infobar));
+  closed_infobar_tracker_.Clear();
   // Destroy the infobar that has just been removed.
   delete removed_infobar;
 
   // But the other tab should still have the info bar...
   ASSERT_EQ(1U, infobar_service_for_tab(0)->infobar_count());
-  ConfirmInfoBarDelegate* infobar_1 =
+  ConfirmInfoBarDelegate* infobar_delegate_1 =
       infobar_service_for_tab(0)->infobar_at(0)->AsConfirmInfoBarDelegate();
-  infobar_1->Cancel();
-  infobar_service_for_tab(0)->RemoveInfoBar(infobar_1);
-  EXPECT_EQ(1U, closed_delegate_tracker_.size());
-  EXPECT_TRUE(closed_delegate_tracker_.Contains(infobar_1));
-  delete infobar_1;
+  infobar_delegate_1->Cancel();
+  infobar_service_for_tab(0)->RemoveInfoBar(infobar_delegate_1);
+  EXPECT_EQ(1U, closed_infobar_tracker_.size());
+  EXPECT_TRUE(closed_infobar_tracker_.Contains(infobar_delegate_1));
+  delete infobar_delegate_1;
 }
 
 TEST_F(GeolocationPermissionContextTests, QueuedOriginMultipleTabs) {
@@ -563,36 +562,35 @@
       infobar_service()->infobar_at(0)->AsConfirmInfoBarDelegate();
 
   // Accept the second tab.
-  ConfirmInfoBarDelegate* infobar_0 =
+  ConfirmInfoBarDelegate* infobar_delegate_0 =
       infobar_service_for_tab(0)->infobar_at(0)->AsConfirmInfoBarDelegate();
-  ASSERT_TRUE(infobar_0);
-  infobar_0->Accept();
+  ASSERT_TRUE(infobar_delegate_0);
+  infobar_delegate_0->Accept();
   CheckPermissionMessageSentForTab(0, 0, true);
-  infobar_service_for_tab(0)->RemoveInfoBar(infobar_0);
-  EXPECT_EQ(2U, closed_delegate_tracker_.size());
-  EXPECT_TRUE(closed_delegate_tracker_.Contains(infobar_0));
-  delete infobar_0;
+  infobar_service_for_tab(0)->RemoveInfoBar(infobar_delegate_0);
+  EXPECT_EQ(2U, closed_infobar_tracker_.size());
+  EXPECT_TRUE(closed_infobar_tracker_.Contains(infobar_delegate_0));
+  delete infobar_delegate_0;
   // Now the infobar for the tab with the same origin should have gone.
   EXPECT_EQ(0U, infobar_service()->infobar_count());
   CheckPermissionMessageSent(0, true);
-  EXPECT_TRUE(closed_delegate_tracker_.Contains(removed_infobar));
-  closed_delegate_tracker_.Clear();
-  // Destroy the infobar that has just been removed.
+  EXPECT_TRUE(closed_infobar_tracker_.Contains(removed_infobar));
+  closed_infobar_tracker_.Clear();
   delete removed_infobar;
 
   // And we should have the queued infobar displayed now.
   ASSERT_EQ(1U, infobar_service_for_tab(0)->infobar_count());
 
   // Accept the second infobar.
-  ConfirmInfoBarDelegate* infobar_1 =
+  ConfirmInfoBarDelegate* infobar_delegate_1 =
       infobar_service_for_tab(0)->infobar_at(0)->AsConfirmInfoBarDelegate();
-  ASSERT_TRUE(infobar_1);
-  infobar_1->Accept();
+  ASSERT_TRUE(infobar_delegate_1);
+  infobar_delegate_1->Accept();
   CheckPermissionMessageSentForTab(0, 1, true);
-  infobar_service_for_tab(0)->RemoveInfoBar(infobar_1);
-  EXPECT_EQ(1U, closed_delegate_tracker_.size());
-  EXPECT_TRUE(closed_delegate_tracker_.Contains(infobar_1));
-  delete infobar_1;
+  infobar_service_for_tab(0)->RemoveInfoBar(infobar_delegate_1);
+  EXPECT_EQ(1U, closed_infobar_tracker_.size());
+  EXPECT_TRUE(closed_infobar_tracker_.Contains(infobar_delegate_1));
+  delete infobar_delegate_1;
 }
 
 TEST_F(GeolocationPermissionContextTests, TabDestroyed) {
@@ -615,18 +613,18 @@
   RequestGeolocationPermission(RequestID(1), requesting_frame_1);
   // Ensure only one infobar is created.
   ASSERT_EQ(1U, infobar_service()->infobar_count());
-  ConfirmInfoBarDelegate* infobar_0 =
+  ConfirmInfoBarDelegate* infobar =
       infobar_service()->infobar_at(0)->AsConfirmInfoBarDelegate();
-  ASSERT_TRUE(infobar_0);
+  ASSERT_TRUE(infobar);
 
   // Delete the tab contents.
   DeleteContents();
-  delete infobar_0;
+  delete infobar;
 
   // During contents destruction, the infobar will have been closed, and the
   // pending request should have been cleared without an infobar being created.
-  ASSERT_EQ(1U, closed_delegate_tracker_.size());
-  ASSERT_TRUE(closed_delegate_tracker_.Contains(infobar_0));
+  ASSERT_EQ(1U, closed_infobar_tracker_.size());
+  ASSERT_TRUE(closed_infobar_tracker_.Contains(infobar));
 }
 
 TEST_F(GeolocationPermissionContextTests, InfoBarUsesCommittedEntry) {
@@ -642,17 +640,17 @@
   RequestGeolocationPermission(RequestID(0), requesting_frame_1);
   // Ensure the infobar is created.
   ASSERT_EQ(1U, infobar_service()->infobar_count());
-  InfoBarDelegate* infobar_0 = infobar_service()->infobar_at(0);
-  ASSERT_TRUE(infobar_0);
+  InfoBarDelegate* infobar_delegate = infobar_service()->infobar_at(0);
+  ASSERT_TRUE(infobar_delegate);
   // Ensure the infobar wouldn't expire for a navigation to the committed entry.
   content::LoadCommittedDetails details;
   details.entry = web_contents()->GetController().GetLastCommittedEntry();
-  EXPECT_FALSE(infobar_0->ShouldExpire(details));
+  EXPECT_FALSE(infobar_delegate->ShouldExpire(details));
   // Ensure the infobar will expire when we commit the pending navigation.
   details.entry = web_contents()->GetController().GetActiveEntry();
-  EXPECT_TRUE(infobar_0->ShouldExpire(details));
+  EXPECT_TRUE(infobar_delegate->ShouldExpire(details));
 
   // Delete the tab contents.
   DeleteContents();
-  delete infobar_0;
+  delete infobar_delegate;
 }
diff --git a/chrome/browser/geolocation/geolocation_browsertest.cc b/chrome/browser/geolocation/geolocation_browsertest.cc
index f5b8439..95158db 100644
--- a/chrome/browser/geolocation/geolocation_browsertest.cc
+++ b/chrome/browser/geolocation/geolocation_browsertest.cc
@@ -9,9 +9,9 @@
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/content_settings/content_settings_usages_state.h"
 #include "chrome/browser/content_settings/host_content_settings_map.h"
 #include "chrome/browser/content_settings/tab_specific_content_settings.h"
-#include "chrome/browser/geolocation/geolocation_settings_state.h"
 #include "chrome/browser/infobars/confirm_infobar_delegate.h"
 #include "chrome/browser/infobars/infobar.h"
 #include "chrome/browser/infobars/infobar_service.h"
@@ -376,9 +376,9 @@
       current_browser_->tab_strip_model()->GetActiveWebContents();
   TabSpecificContentSettings* content_settings =
       TabSpecificContentSettings::FromWebContents(web_contents);
-  const GeolocationSettingsState& settings_state =
-      content_settings->geolocation_settings_state();
-  size_t state_map_size = settings_state.state_map().size();
+  const ContentSettingsUsagesState& usages_state =
+      content_settings->geolocation_usages_state();
+  size_t state_map_size = usages_state.state_map().size();
   ASSERT_TRUE(infobar_);
   LOG(WARNING) << "will set infobar response";
   {
@@ -395,13 +395,13 @@
   InfoBarService::FromWebContents(web_contents)->RemoveInfoBar(infobar_);
   LOG(WARNING) << "infobar response set";
   infobar_ = NULL;
-  EXPECT_GT(settings_state.state_map().size(), state_map_size);
+  EXPECT_GT(usages_state.state_map().size(), state_map_size);
   GURL requesting_origin(requesting_url.GetOrigin());
-  EXPECT_EQ(1U, settings_state.state_map().count(requesting_origin));
+  EXPECT_EQ(1U, usages_state.state_map().count(requesting_origin));
   ContentSetting expected_setting =
         allowed ? CONTENT_SETTING_ALLOW : CONTENT_SETTING_BLOCK;
   EXPECT_EQ(expected_setting,
-            settings_state.state_map().find(requesting_origin)->second);
+            usages_state.state_map().find(requesting_origin)->second);
 }
 
 void GeolocationBrowserTest::CheckStringValueFromJavascriptForTab(
diff --git a/chrome/browser/geolocation/geolocation_infobar_delegate.cc b/chrome/browser/geolocation/geolocation_infobar_delegate.cc
index 93f500d..017c570 100644
--- a/chrome/browser/geolocation/geolocation_infobar_delegate.cc
+++ b/chrome/browser/geolocation/geolocation_infobar_delegate.cc
@@ -31,8 +31,11 @@
     const GeolocationPermissionRequestID& id,
     const GURL& requesting_frame,
     const std::string& display_languages) {
+  const content::NavigationEntry* committed_entry =
+      infobar_service->web_contents()->GetController().GetLastCommittedEntry();
   return infobar_service->AddInfoBar(scoped_ptr<InfoBarDelegate>(
       new DelegateType(infobar_service, controller, id, requesting_frame,
+                       committed_entry ? committed_entry->GetUniqueID() : 0,
                        display_languages)));
 }
 
@@ -41,15 +44,14 @@
     GeolocationInfoBarQueueController* controller,
     const GeolocationPermissionRequestID& id,
     const GURL& requesting_frame,
+    int contents_unique_id,
     const std::string& display_languages)
     : ConfirmInfoBarDelegate(infobar_service),
       controller_(controller),
       id_(id),
       requesting_frame_(requesting_frame),
+      contents_unique_id_(contents_unique_id),
       display_languages_(display_languages) {
-  const content::NavigationEntry* committed_entry = infobar_service->
-      web_contents()->GetController().GetLastCommittedEntry();
-   contents_unique_id_ = committed_entry ? committed_entry->GetUniqueID() : 0;
 }
 
 GeolocationInfoBarDelegate::~GeolocationInfoBarDelegate() {
diff --git a/chrome/browser/geolocation/geolocation_infobar_delegate.h b/chrome/browser/geolocation/geolocation_infobar_delegate.h
index f1656ad..4e63f64 100644
--- a/chrome/browser/geolocation/geolocation_infobar_delegate.h
+++ b/chrome/browser/geolocation/geolocation_infobar_delegate.h
@@ -19,8 +19,8 @@
 // and handling of geolocation permission infobars to the user.
 class GeolocationInfoBarDelegate : public ConfirmInfoBarDelegate {
  public:
-  // Creates a geolocation delegate and adds it to |infobar_service|.  Returns
-  // the delegate if it was successfully added.
+  // Creates a geolocation infobar delegate and adds it to |infobar_service|.
+  // Returns the delegate if it was successfully added.
   static InfoBarDelegate* Create(InfoBarService* infobar_service,
                                  GeolocationInfoBarQueueController* controller,
                                  const GeolocationPermissionRequestID& id,
@@ -32,6 +32,7 @@
                              GeolocationInfoBarQueueController* controller,
                              const GeolocationPermissionRequestID& id,
                              const GURL& requesting_frame,
+                             int contents_unique_id,
                              const std::string& display_languages);
   virtual ~GeolocationInfoBarDelegate();
 
@@ -53,7 +54,6 @@
   virtual string16 GetLinkText() const OVERRIDE;
   virtual bool LinkClicked(WindowOpenDisposition disposition) OVERRIDE;
 
- private:
   GeolocationInfoBarQueueController* controller_;
   const GeolocationPermissionRequestID id_;
   GURL requesting_frame_;
diff --git a/chrome/browser/geolocation/geolocation_infobar_delegate_android.cc b/chrome/browser/geolocation/geolocation_infobar_delegate_android.cc
index 062e200..032b7f4 100644
--- a/chrome/browser/geolocation/geolocation_infobar_delegate_android.cc
+++ b/chrome/browser/geolocation/geolocation_infobar_delegate_android.cc
@@ -16,9 +16,11 @@
     GeolocationInfoBarQueueController* controller,
     const GeolocationPermissionRequestID& id,
     const GURL& requesting_frame_url,
+    int contents_unique_id,
     const std::string& display_languages)
     : GeolocationInfoBarDelegate(infobar_service, controller, id,
-                                 requesting_frame_url, display_languages),
+                                 requesting_frame_url, contents_unique_id,
+                                 display_languages),
       google_location_settings_helper_(
           GoogleLocationSettingsHelper::Create()) {
 }
diff --git a/chrome/browser/geolocation/geolocation_infobar_delegate_android.h b/chrome/browser/geolocation/geolocation_infobar_delegate_android.h
index 7f1a210..f5059e3 100644
--- a/chrome/browser/geolocation/geolocation_infobar_delegate_android.h
+++ b/chrome/browser/geolocation/geolocation_infobar_delegate_android.h
@@ -17,6 +17,7 @@
       GeolocationInfoBarQueueController* controller,
       const GeolocationPermissionRequestID& id,
       const GURL& requesting_frame_url,
+      int contents_unique_id,
       const std::string& display_languages);
 
  private:
diff --git a/chrome/browser/geolocation/geolocation_infobar_queue_controller.cc b/chrome/browser/geolocation/geolocation_infobar_queue_controller.cc
index 6607c25..69eb13e 100644
--- a/chrome/browser/geolocation/geolocation_infobar_queue_controller.cc
+++ b/chrome/browser/geolocation/geolocation_infobar_queue_controller.cc
@@ -49,19 +49,19 @@
 
   const GeolocationPermissionRequestID& id() const { return id_; }
   const GURL& requesting_frame() const { return requesting_frame_; }
-  bool has_infobar_delegate() const { return !!infobar_delegate_; }
-  InfoBarDelegate* infobar_delegate() { return infobar_delegate_; }
+  bool has_infobar() const { return !!infobar_; }
+  InfoBarDelegate* infobar() { return infobar_; }
 
   void RunCallback(bool allowed);
-  void CreateInfoBarDelegate(GeolocationInfoBarQueueController* controller,
-                             const std::string& display_languages);
+  void CreateInfoBar(GeolocationInfoBarQueueController* controller,
+                     const std::string& display_languages);
 
  private:
   GeolocationPermissionRequestID id_;
   GURL requesting_frame_;
   GURL embedder_;
   PermissionDecidedCallback callback_;
-  InfoBarDelegate* infobar_delegate_;
+  InfoBarDelegate* infobar_;
 
   // Purposefully do not disable copying, as this is stored in STL containers.
 };
@@ -75,7 +75,7 @@
       requesting_frame_(requesting_frame),
       embedder_(embedder),
       callback_(callback),
-      infobar_delegate_(NULL) {
+      infobar_(NULL) {
 }
 
 GeolocationInfoBarQueueController::PendingInfoBarRequest::
@@ -94,9 +94,9 @@
 }
 
 void GeolocationInfoBarQueueController::PendingInfoBarRequest::
-    CreateInfoBarDelegate(GeolocationInfoBarQueueController* controller,
-                          const std::string& display_languages) {
-  infobar_delegate_ = GeolocationInfoBarDelegate::Create(
+    CreateInfoBar(GeolocationInfoBarQueueController* controller,
+                  const std::string& display_languages) {
+  infobar_ = GeolocationInfoBarDelegate::Create(
       GetInfoBarService(id_), controller, id_, requesting_frame_,
       display_languages);
 }
@@ -138,8 +138,8 @@
   for (PendingInfoBarRequests::iterator i(pending_infobar_requests_.begin());
        i != pending_infobar_requests_.end(); ++i) {
     if (i->id().Equals(id)) {
-      if (i->has_infobar_delegate())
-        GetInfoBarService(id)->RemoveInfoBar(i->infobar_delegate());
+      if (i->has_infobar())
+        GetInfoBarService(id)->RemoveInfoBar(i->infobar());
       else
         pending_infobar_requests_.erase(i);
       return;
@@ -167,18 +167,18 @@
     if (i->IsForPair(requesting_frame, embedder)) {
       requests_to_notify.push_back(*i);
       if (i->id().Equals(id)) {
-        // The delegate that called us is i, and it's currently in either
-        // Accept() or Cancel(). This means that the owning InfoBar will call
-        // RemoveInfoBar() later on, and that will trigger a notification we're
+        // The infobar that called us is i->infobar(), and it's currently in
+        // either Accept() or Cancel(). This means that RemoveInfoBar() will be
+        // called later on, and that will trigger a notification we're
         // observing.
         ++i;
-      } else if (i->has_infobar_delegate()) {
-        // This InfoBar is for the same frame/embedder pair, but in a different
+      } else if (i->has_infobar()) {
+        // This infobar is for the same frame/embedder pair, but in a different
         // tab. We should remove it now that we've got an answer for it.
         infobars_to_remove.push_back(*i);
         ++i;
       } else {
-        // We haven't created an InfoBar yet, just remove the pending request.
+        // We haven't created an infobar yet, just remove the pending request.
         i = pending_infobar_requests_.erase(i);
       }
     } else {
@@ -186,10 +186,10 @@
     }
   }
 
-  // Remove all InfoBars for the same |requesting_frame| and |embedder|.
+  // Remove all infobars for the same |requesting_frame| and |embedder|.
   for (PendingInfoBarRequests::iterator i = infobars_to_remove.begin();
        i != infobars_to_remove.end(); ++i)
-    GetInfoBarService(i->id())->RemoveInfoBar(i->infobar_delegate());
+    GetInfoBarService(i->id())->RemoveInfoBar(i->infobar());
 
   // Send out the permission notifications.
   for (PendingInfoBarRequests::iterator i = requests_to_notify.begin();
@@ -205,17 +205,17 @@
   // We will receive this notification for all infobar closures, so we need to
   // check whether this is the geolocation infobar we're tracking. Note that the
   // InfoBarContainer (if any) may have received this notification before us and
-  // caused the delegate to be deleted, so it's not safe to dereference the
-  // contents of the delegate. The address of the delegate, however, is OK to
+  // caused the infobar to be deleted, so it's not safe to dereference the
+  // contents of the infobar. The address of the infobar, however, is OK to
   // use to find the PendingInfoBarRequest to remove because
   // pending_infobar_requests_ will not have received any new entries between
   // the NotificationService's call to InfoBarContainer::Observe and this
   // method.
-  InfoBarDelegate* delegate =
+  InfoBarDelegate* infobar =
       content::Details<InfoBarRemovedDetails>(details)->first;
   for (PendingInfoBarRequests::iterator i = pending_infobar_requests_.begin();
        i != pending_infobar_requests_.end(); ++i) {
-    if (i->infobar_delegate() == delegate) {
+    if (i->infobar() == infobar) {
       GeolocationPermissionRequestID id(i->id());
       pending_infobar_requests_.erase(i);
       ShowQueuedInfoBarForTab(id);
@@ -229,7 +229,7 @@
   for (PendingInfoBarRequests::const_iterator i(
            pending_infobar_requests_.begin());
        i != pending_infobar_requests_.end(); ++i) {
-    if (i->id().IsForSameTabAs(id) && i->has_infobar_delegate())
+    if (i->id().IsForSameTabAs(id) && i->has_infobar())
       return true;
   }
   return false;
@@ -253,9 +253,9 @@
 
   for (PendingInfoBarRequests::iterator i = pending_infobar_requests_.begin();
        i != pending_infobar_requests_.end(); ++i) {
-    if (i->id().IsForSameTabAs(id) && !i->has_infobar_delegate()) {
+    if (i->id().IsForSameTabAs(id) && !i->has_infobar()) {
       RegisterForInfoBarNotifications(infobar_service);
-      i->CreateInfoBarDelegate(
+      i->CreateInfoBar(
           this, profile_->GetPrefs()->GetString(prefs::kAcceptLanguages));
       return;
     }
@@ -269,7 +269,7 @@
   for (PendingInfoBarRequests::iterator i = pending_infobar_requests_.begin();
        i != pending_infobar_requests_.end(); ) {
     if (i->id().IsForSameTabAs(id)) {
-      DCHECK(!i->has_infobar_delegate());
+      DCHECK(!i->has_infobar());
       i = pending_infobar_requests_.erase(i);
     } else {
       ++i;
diff --git a/chrome/browser/google/google_url_tracker.cc b/chrome/browser/google/google_url_tracker.cc
index 4ed0c28..768de18 100644
--- a/chrome/browser/google/google_url_tracker.cc
+++ b/chrome/browser/google/google_url_tracker.cc
@@ -343,10 +343,10 @@
   if (map_entry->has_infobar_delegate()) {
     map_entry->infobar_delegate()->Update(search_url);
   } else {
-    GoogleURLTrackerInfoBarDelegate* infobar_delegate =
+    GoogleURLTrackerInfoBarDelegate* infobar =
         infobar_creator_.Run(infobar_service, this, search_url);
-    if (infobar_delegate)
-      map_entry->SetInfoBarDelegate(infobar_delegate);
+    if (infobar)
+      map_entry->SetInfoBarDelegate(infobar);
     else
       map_entry->Close(false);
   }
@@ -354,14 +354,14 @@
 
 void GoogleURLTracker::OnTabClosed(
     content::NavigationController* navigation_controller) {
-  // Because InfoBarService tears itself down in on tab destruction, it may
-  // or may not be possible to get a non-NULL InfoBarService pointer here,
-  // depending on which order notifications fired in.  Likewise, the pointer in
-  // |entry_map_| (and in its associated MapEntry) may point to deleted memory.
-  // Therefore, if we were to access to the InfoBarService* we have for this
-  // tab, we'd need to ensure we just looked at the raw pointer value, and never
-  // dereferenced it.  This function doesn't need to do even that, but others in
-  // the call chain from here might (and have comments pointing back here).
+  // Because InfoBarService tears itself down on tab destruction, it's possible
+  // to get a non-NULL InfoBarService pointer here, depending on which order
+  // notifications fired in.  Likewise, the pointer in |entry_map_| (and in its
+  // associated MapEntry) may point to deleted memory.  Therefore, if we were to
+  // access the InfoBarService* we have for this tab, we'd need to ensure we
+  // just looked at the raw pointer value, and never dereferenced it.  This
+  // function doesn't need to do even that, but others in the call chain from
+  // here might (and have comments pointing back here).
   for (EntryMap::iterator i(entry_map_.begin()); i != entry_map_.end(); ++i) {
     if (i->second->navigation_controller() == navigation_controller) {
       i->second->Close(false);
diff --git a/chrome/browser/google/google_url_tracker_infobar_delegate.h b/chrome/browser/google/google_url_tracker_infobar_delegate.h
index 7e01655..b0be8f5 100644
--- a/chrome/browser/google/google_url_tracker_infobar_delegate.h
+++ b/chrome/browser/google/google_url_tracker_infobar_delegate.h
@@ -14,8 +14,8 @@
 // changed.
 class GoogleURLTrackerInfoBarDelegate : public ConfirmInfoBarDelegate {
  public:
-  // Creates a Google URL tracker delegate and adds it to |infobar_service|.
-  // Returns the delegate if it was successfully added.
+  // Creates a Google URL tracker infobar delegate and adds it to
+  // |infobar_service|.  Returns the delegate if it was successfully added.
   static GoogleURLTrackerInfoBarDelegate* Create(
       InfoBarService* infobar_service,
       GoogleURLTracker* google_url_tracker,
diff --git a/chrome/browser/google/google_url_tracker_unittest.cc b/chrome/browser/google/google_url_tracker_unittest.cc
index 3a1d676..88bdc5a 100644
--- a/chrome/browser/google/google_url_tracker_unittest.cc
+++ b/chrome/browser/google/google_url_tracker_unittest.cc
@@ -33,10 +33,10 @@
 class TestInfoBarDelegate : public GoogleURLTrackerInfoBarDelegate {
  public:
   // Creates a test delegate and returns it.  Unlike the parent class, this does
-  // not create add the infobar to |infobar_service|, since that "pointer" is
-  // really just a magic number.  Thus there is no InfoBarService ownership of
-  // the returned object; and since the caller doesn't own the returned object,
-  // we rely on |test_harness| cleaning this up eventually in
+  // not add the infobar to |infobar_service|, since that "pointer" is really
+  // just a magic number.  Thus there is no InfoBarService ownership of the
+  // returned object; and since the caller doesn't own the returned object, we
+  // rely on |test_harness| cleaning this up eventually in
   // GoogleURLTrackerTest::OnInfoBarClosed() to avoid leaks.
   static GoogleURLTrackerInfoBarDelegate* Create(
       GoogleURLTrackerTest* test_harness,
@@ -201,7 +201,7 @@
 class GoogleURLTrackerTest : public testing::Test {
  public:
   // Called by TestInfoBarDelegate::Close().
-  void OnInfoBarClosed(InfoBarDelegate* infobar,
+  void OnInfoBarClosed(scoped_ptr<InfoBarDelegate> infobar,
                        InfoBarService* infobar_service);
 
  protected:
@@ -265,10 +265,10 @@
   std::set<int> unique_ids_seen_;
 };
 
-void GoogleURLTrackerTest::OnInfoBarClosed(InfoBarDelegate* infobar,
+void GoogleURLTrackerTest::OnInfoBarClosed(scoped_ptr<InfoBarDelegate> infobar,
                                            InfoBarService* infobar_service) {
   // First, simulate the InfoBarService firing INFOBAR_REMOVED.
-  InfoBarRemovedDetails removed_details(infobar, false);
+  InfoBarRemovedDetails removed_details(infobar.get(), false);
   GoogleURLTracker::EntryMap::const_iterator i =
       google_url_tracker_->entry_map_.find(infobar_service);
   ASSERT_FALSE(i == google_url_tracker_->entry_map_.end());
@@ -279,7 +279,7 @@
                      content::Details<InfoBarRemovedDetails>(&removed_details));
 
   // Second, simulate the infobar container closing the infobar in response.
-  delete infobar;
+  // This happens automatically as |infobar| goes out of scope.
 }
 
 GoogleURLTrackerTest::GoogleURLTrackerTest()
@@ -491,7 +491,8 @@
 }
 
 void TestInfoBarDelegate::Close(bool redo_search) {
-  test_harness_->OnInfoBarClosed(this, infobar_service_);
+  test_harness_->OnInfoBarClosed(scoped_ptr<InfoBarDelegate>(this),
+                                 infobar_service_);
   // WARNING: At this point |this| has been deleted!
 }
 
diff --git a/chrome/browser/google_apis/task_util.h b/chrome/browser/google_apis/task_util.h
index 3c72beb..d186f3d 100644
--- a/chrome/browser/google_apis/task_util.h
+++ b/chrome/browser/google_apis/task_util.h
@@ -19,6 +19,16 @@
 // Implementation of the composed callback, whose signature is |Sig|.
 template<typename Sig> struct ComposedCallback;
 
+// ComposedCallback with no argument.
+template<>
+struct ComposedCallback<void()> {
+  static void Run(
+      const base::Callback<void(const base::Closure&)>& runner,
+      const base::Closure& callback) {
+    runner.Run(callback);
+  }
+};
+
 // ComposedCallback with one argument.
 template<typename T1>
 struct ComposedCallback<void(T1)> {
diff --git a/chrome/browser/hang_monitor/hung_plugin_action.cc b/chrome/browser/hang_monitor/hung_plugin_action.cc
index e2133b0..cdb9e59 100644
--- a/chrome/browser/hang_monitor/hung_plugin_action.cc
+++ b/chrome/browser/hang_monitor/hung_plugin_action.cc
@@ -10,11 +10,11 @@
 #include "base/version.h"
 #include "chrome/browser/ui/simple_message_box.h"
 #include "chrome/common/logging_chrome.h"
+#include "content/public/browser/plugin_service.h"
+#include "content/public/common/webplugininfo.h"
 #include "grit/generated_resources.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/win/hwnd_util.h"
-#include "webkit/plugins/npapi/plugin_utils.h"
-#include "webkit/plugins/npapi/webplugin_delegate_impl.h"
 
 namespace {
 
@@ -41,7 +41,7 @@
 GTalkPluginLogVersion GetGTalkPluginVersion(const string16& version) {
   int gtalk_plugin_version = GTALK_PLUGIN_VERSION_MIN;
   Version plugin_version;
-  webkit::npapi::CreateVersionFromString(version, &plugin_version);
+  content::WebPluginInfo::CreateVersionFromString(version, &plugin_version);
   if (plugin_version.IsValid() && plugin_version.components().size() >= 2) {
     gtalk_plugin_version = 10 * plugin_version.components()[0] +
         plugin_version.components()[1] - kGTalkPluginLogMinVersion;
@@ -175,10 +175,8 @@
       // we have gone too far.
       return false;
     }
-    if (webkit::npapi::WebPluginDelegateImpl::GetPluginNameFromWindow(
-            window_to_check, plugin_name)) {
-      webkit::npapi::WebPluginDelegateImpl::GetPluginVersionFromWindow(
-          window_to_check, plugin_version);
+    if (content::PluginService::GetInstance()->GetPluginInfoFromWindow(
+            window_to_check, plugin_name, plugin_version)) {
       return true;
     }
     window_to_check = GetParent(window_to_check);
diff --git a/chrome/browser/history/archived_database.cc b/chrome/browser/history/archived_database.cc
index ab114d2..468416e 100644
--- a/chrome/browser/history/archived_database.cc
+++ b/chrome/browser/history/archived_database.cc
@@ -74,6 +74,10 @@
   return transaction.Commit();
 }
 
+void ArchivedDatabase::TrimMemory(bool aggressively) {
+  db_.TrimMemory(aggressively);
+}
+
 void ArchivedDatabase::BeginTransaction() {
   db_.BeginTransaction();
 }
diff --git a/chrome/browser/history/archived_database.h b/chrome/browser/history/archived_database.h
index 0fe7184..3bf896a 100644
--- a/chrome/browser/history/archived_database.h
+++ b/chrome/browser/history/archived_database.h
@@ -34,6 +34,10 @@
   // functions on this class are called.
   bool Init(const base::FilePath& file_name);
 
+  // Try to trim the cache memory used by the database.  If |aggressively| is
+  // true try to trim all unused cache, otherwise trim by half.
+  void TrimMemory(bool aggressively);
+
   // Transactions on the database. We support nested transactions and only
   // commit when the outermost one is committed (sqlite doesn't support true
   // nested transactions).
diff --git a/chrome/browser/history/history_backend.cc b/chrome/browser/history/history_backend.cc
index a5a0cca..adaff5a 100644
--- a/chrome/browser/history/history_backend.cc
+++ b/chrome/browser/history/history_backend.cc
@@ -260,6 +260,8 @@
     InitImpl(languages);
   delegate_->DBLoaded(id_);
   typed_url_syncable_service_.reset(new TypedUrlSyncableService(this));
+  memory_pressure_listener_.reset(new base::MemoryPressureListener(
+      base::Bind(&HistoryBackend::OnMemoryPressure, base::Unretained(this))));
 #if defined(OS_ANDROID)
   PopulateMostVisitedURLMap();
 #endif
@@ -766,6 +768,18 @@
                   TimeTicks::Now() - beginning_time);
 }
 
+void HistoryBackend::OnMemoryPressure(
+    base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) {
+  bool trim_aggressively = memory_pressure_level ==
+      base::MemoryPressureListener::MEMORY_PRESSURE_CRITICAL;
+  if (db_)
+    db_->TrimMemory(trim_aggressively);
+  if (thumbnail_db_)
+    thumbnail_db_->TrimMemory(trim_aggressively);
+  if (archived_db_)
+    archived_db_->TrimMemory(trim_aggressively);
+}
+
 void HistoryBackend::CloseAllDatabases() {
   if (db_) {
     // Commit the long-running transaction.
diff --git a/chrome/browser/history/history_backend.h b/chrome/browser/history/history_backend.h
index fbc17a9..c4010b7 100644
--- a/chrome/browser/history/history_backend.h
+++ b/chrome/browser/history/history_backend.h
@@ -13,6 +13,7 @@
 #include "base/containers/mru_cache.h"
 #include "base/files/file_path.h"
 #include "base/gtest_prod_util.h"
+#include "base/memory/memory_pressure_listener.h"
 #include "base/memory/scoped_ptr.h"
 #include "chrome/browser/history/archived_database.h"
 #include "chrome/browser/history/expire_history_backend.h"
@@ -598,6 +599,10 @@
   // Does the work of Init.
   void InitImpl(const std::string& languages);
 
+  // Called when the system is under memory pressure.
+  void OnMemoryPressure(
+      base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level);
+
   // Closes all databases managed by HistoryBackend. Commits any pending
   // transactions.
   void CloseAllDatabases();
@@ -939,6 +944,9 @@
   // before Init is called.
   scoped_ptr<TypedUrlSyncableService> typed_url_syncable_service_;
 
+  // Listens for the system being under memory pressure.
+  scoped_ptr<base::MemoryPressureListener> memory_pressure_listener_;
+
   DISALLOW_COPY_AND_ASSIGN(HistoryBackend);
 };
 
diff --git a/chrome/browser/history/history_database.cc b/chrome/browser/history/history_database.cc
index 43ce119..3db7acd 100644
--- a/chrome/browser/history/history_database.cc
+++ b/chrome/browser/history/history_database.cc
@@ -237,6 +237,10 @@
   ignore_result(db_.Execute("VACUUM"));
 }
 
+void HistoryDatabase::TrimMemory(bool aggressively) {
+  db_.TrimMemory(aggressively);
+}
+
 bool HistoryDatabase::Raze() {
   return db_.Raze();
 }
diff --git a/chrome/browser/history/history_database.h b/chrome/browser/history/history_database.h
index 01df342..5aac5ba 100644
--- a/chrome/browser/history/history_database.h
+++ b/chrome/browser/history/history_database.h
@@ -131,6 +131,10 @@
   // unused space in the file. It can be VERY SLOW.
   void Vacuum();
 
+  // Try to trim the cache memory used by the database.  If |aggressively| is
+  // true try to trim all unused cache, otherwise trim by half.
+  void TrimMemory(bool aggressively);
+
   // Razes the database. Returns true if successful.
   bool Raze();
 
diff --git a/chrome/browser/history/snippet.cc b/chrome/browser/history/snippet.cc
index 90d80d0..e1069a6 100644
--- a/chrome/browser/history/snippet.cc
+++ b/chrome/browser/history/snippet.cc
@@ -11,9 +11,9 @@
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
-#include "third_party/icu/public/common/unicode/brkiter.h"
-#include "third_party/icu/public/common/unicode/utext.h"
-#include "third_party/icu/public/common/unicode/utf8.h"
+#include "third_party/icu/source/common/unicode/brkiter.h"
+#include "third_party/icu/source/common/unicode/utext.h"
+#include "third_party/icu/source/common/unicode/utf8.h"
 
 namespace {
 
diff --git a/chrome/browser/history/thumbnail_database.cc b/chrome/browser/history/thumbnail_database.cc
index da34646..51cbac1 100644
--- a/chrome/browser/history/thumbnail_database.cc
+++ b/chrome/browser/history/thumbnail_database.cc
@@ -582,6 +582,10 @@
   ignore_result(db_.Execute("VACUUM"));
 }
 
+void ThumbnailDatabase::TrimMemory(bool aggressively) {
+  db_.TrimMemory(aggressively);
+}
+
 bool ThumbnailDatabase::SetPageThumbnail(
     const GURL& url,
     URLID id,
diff --git a/chrome/browser/history/thumbnail_database.h b/chrome/browser/history/thumbnail_database.h
index 00931f1..ae4006d 100644
--- a/chrome/browser/history/thumbnail_database.h
+++ b/chrome/browser/history/thumbnail_database.h
@@ -74,6 +74,10 @@
   // unused space in the file. It can be VERY SLOW.
   void Vacuum();
 
+  // Try to trim the cache memory used by the database.  If |aggressively| is
+  // true try to trim all unused cache, otherwise trim by half.
+  void TrimMemory(bool aggressively);
+
   // Thumbnails ----------------------------------------------------------------
 
   // Sets the given data to be the thumbnail for the given URL,
diff --git a/chrome/browser/history/web_history_service.h b/chrome/browser/history/web_history_service.h
index dceb815..3a234a2 100644
--- a/chrome/browser/history/web_history_service.h
+++ b/chrome/browser/history/web_history_service.h
@@ -5,6 +5,7 @@
 #ifndef CHROME_BROWSER_HISTORY_WEB_HISTORY_SERVICE_H_
 #define CHROME_BROWSER_HISTORY_WEB_HISTORY_SERVICE_H_
 
+#include "base/memory/weak_ptr.h"
 #include "chrome/browser/history/history_types.h"
 #include "chrome/browser/profiles/profile.h"
 #include "components/browser_context_keyed_service/browser_context_keyed_service.h"
diff --git a/chrome/browser/icon_loader_chromeos.cc b/chrome/browser/icon_loader_chromeos.cc
index db95067..1329845 100644
--- a/chrome/browser/icon_loader_chromeos.cc
+++ b/chrome/browser/icon_loader_chromeos.cc
@@ -12,7 +12,7 @@
 #include "base/files/file_path.h"
 #include "base/lazy_instance.h"
 #include "base/memory/ref_counted_memory.h"
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "base/strings/string_util.h"
 #include "chrome/browser/icon_loader.h"
 #include "grit/theme_resources.h"
diff --git a/chrome/browser/icon_loader_linux.cc b/chrome/browser/icon_loader_linux.cc
index b75da17..4d400a9 100644
--- a/chrome/browser/icon_loader_linux.cc
+++ b/chrome/browser/icon_loader_linux.cc
@@ -9,7 +9,7 @@
 #include "base/bind.h"
 #include "base/file_util.h"
 #include "base/logging.h"
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "base/nix/mime_util_xdg.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/gfx/codec/png_codec.h"
diff --git a/chrome/browser/icon_loader_mac.mm b/chrome/browser/icon_loader_mac.mm
index 4a93736..be2eecf 100644
--- a/chrome/browser/icon_loader_mac.mm
+++ b/chrome/browser/icon_loader_mac.mm
@@ -8,9 +8,9 @@
 
 #include "base/bind.h"
 #include "base/files/file_path.h"
-#include "base/message_loop.h"
-#include "base/threading/thread.h"
+#include "base/message_loop/message_loop.h"
 #include "base/strings/sys_string_conversions.h"
+#include "base/threading/thread.h"
 #include "ui/gfx/image/image_skia.h"
 #include "ui/gfx/image/image_skia_util_mac.h"
 
diff --git a/chrome/browser/icon_loader_win.cc b/chrome/browser/icon_loader_win.cc
index 62cb6f0..fe826f0 100644
--- a/chrome/browser/icon_loader_win.cc
+++ b/chrome/browser/icon_loader_win.cc
@@ -8,7 +8,7 @@
 #include <shellapi.h>
 
 #include "base/bind.h"
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "base/threading/thread.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/gfx/icon_util.h"
diff --git a/chrome/browser/importer/external_process_importer_client.cc b/chrome/browser/importer/external_process_importer_client.cc
index 7861c9c..aa7199e 100644
--- a/chrome/browser/importer/external_process_importer_client.cc
+++ b/chrome/browser/importer/external_process_importer_client.cc
@@ -296,6 +296,9 @@
   // in the external process.
   DictionaryValue localized_strings;
   localized_strings.SetString(
+      base::IntToString(IDS_BOOKMARK_GROUP),
+      l10n_util::GetStringUTF8(IDS_BOOKMARK_GROUP));
+  localized_strings.SetString(
       base::IntToString(IDS_BOOKMARK_GROUP_FROM_FIREFOX),
       l10n_util::GetStringUTF8(IDS_BOOKMARK_GROUP_FROM_FIREFOX));
   localized_strings.SetString(
@@ -305,6 +308,9 @@
       base::IntToString(IDS_IMPORT_FROM_FIREFOX),
       l10n_util::GetStringUTF8(IDS_IMPORT_FROM_FIREFOX));
   localized_strings.SetString(
+      base::IntToString(IDS_IMPORT_FROM_ICEWEASEL),
+      l10n_util::GetStringUTF8(IDS_IMPORT_FROM_ICEWEASEL));
+  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_host.cc b/chrome/browser/importer/external_process_importer_host.cc
index 2615d00..4a25adc 100644
--- a/chrome/browser/importer/external_process_importer_host.cc
+++ b/chrome/browser/importer/external_process_importer_host.cc
@@ -171,7 +171,7 @@
 
 bool ExternalProcessImporterHost::CheckForFirefoxLock(
     const importer::SourceProfile& source_profile) {
-  if (source_profile.importer_type != importer::TYPE_FIREFOX3)
+  if (source_profile.importer_type != importer::TYPE_FIREFOX)
     return true;
 
   DCHECK(!firefox_lock_.get());
diff --git a/chrome/browser/importer/firefox_importer_browsertest.cc b/chrome/browser/importer/firefox_importer_browsertest.cc
index 0290ba2..8082e76 100644
--- a/chrome/browser/importer/firefox_importer_browsertest.cc
+++ b/chrome/browser/importer/firefox_importer_browsertest.cc
@@ -5,7 +5,7 @@
 #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/message_loop.h"
 #include "base/path_service.h"
 #include "base/stl_util.h"
 #include "base/strings/string16.h"
@@ -50,7 +50,7 @@
   const char* url;
 };
 
-const BookmarkInfo kFirefox3Bookmarks[] = {
+const BookmarkInfo kFirefoxBookmarks[] = {
   {true, 1, {L"Bookmarks Toolbar"},
     L"Toolbar",
     "http://site/"},
@@ -59,14 +59,14 @@
     "http://www.google.com/"},
 };
 
-const PasswordInfo kFirefox3Passwords[] = {
+const PasswordInfo kFirefoxPasswords[] = {
   {"http://localhost:8080/", "http://localhost:8080/", "http://localhost:8080/",
     L"loginuser", L"abc", L"loginpass", L"123", false},
   {"http://localhost:8080/", "", "http://localhost:8080/localhost",
     L"", L"http", L"", L"Http1+1abcdefg", false},
 };
 
-const KeywordInfo kFirefox3Keywords[] = {
+const KeywordInfo kFirefoxKeywords[] = {
   { L"amazon.com",
     "http://www.amazon.com/exec/obidos/external-search/?field-keywords="
     "{searchTerms}&mode=blended" },
@@ -94,17 +94,17 @@
   { L"\x4E2D\x6587", "http://www.google.com/" },
 };
 
-const int kDefaultFirefox3KeywordIndex = 8;
+const int kDefaultFirefoxKeywordIndex = 8;
 
-class Firefox3Observer : public ProfileWriter,
-                         public importer::ImporterProgressObserver {
+class FirefoxObserver : public ProfileWriter,
+                        public importer::ImporterProgressObserver {
  public:
-  Firefox3Observer()
+  FirefoxObserver()
       : ProfileWriter(NULL), bookmark_count_(0), history_count_(0),
         password_count_(0), keyword_count_(0), import_search_engines_(true) {
   }
 
-  explicit Firefox3Observer(bool import_search_engines)
+  explicit FirefoxObserver(bool import_search_engines)
       : ProfileWriter(NULL), bookmark_count_(0), history_count_(0),
         password_count_(0), keyword_count_(0),
         import_search_engines_(import_search_engines) {
@@ -116,11 +116,11 @@
   virtual void ImportItemEnded(importer::ImportItem item) OVERRIDE {}
   virtual void ImportEnded() OVERRIDE {
     base::MessageLoop::current()->Quit();
-    EXPECT_EQ(arraysize(kFirefox3Bookmarks), bookmark_count_);
+    EXPECT_EQ(arraysize(kFirefoxBookmarks), bookmark_count_);
     EXPECT_EQ(1U, history_count_);
-    EXPECT_EQ(arraysize(kFirefox3Passwords), password_count_);
+    EXPECT_EQ(arraysize(kFirefoxPasswords), password_count_);
     if (import_search_engines_)
-      EXPECT_EQ(arraysize(kFirefox3Keywords), keyword_count_);
+      EXPECT_EQ(arraysize(kFirefoxKeywords), keyword_count_);
   }
 
   virtual bool BookmarkModelIsLoaded() const OVERRIDE {
@@ -133,7 +133,7 @@
   }
 
   virtual void AddPasswordForm(const content::PasswordForm& form) OVERRIDE {
-    PasswordInfo p = kFirefox3Passwords[password_count_];
+    PasswordInfo p = kFirefoxPasswords[password_count_];
     EXPECT_EQ(p.origin, form.origin.spec());
     EXPECT_EQ(p.realm, form.signon_realm);
     EXPECT_EQ(p.action, form.action.spec());
@@ -161,14 +161,13 @@
 
   virtual void AddBookmarks(const std::vector<ImportedBookmarkEntry>& bookmarks,
                             const string16& top_level_folder_name) OVERRIDE {
-    ASSERT_LE(bookmark_count_ + bookmarks.size(),
-              arraysize(kFirefox3Bookmarks));
+    ASSERT_LE(bookmark_count_ + bookmarks.size(), arraysize(kFirefoxBookmarks));
     // Importer should import the FF favorites the same as the list, in the same
     // order.
     for (size_t i = 0; i < bookmarks.size(); ++i) {
       EXPECT_NO_FATAL_FAILURE(
           TestEqualBookmarkEntry(bookmarks[i],
-                                 kFirefox3Bookmarks[bookmark_count_])) << i;
+                                 kFirefoxBookmarks[bookmark_count_])) << i;
       ++bookmark_count_;
     }
   }
@@ -180,10 +179,10 @@
       // that template URL.
       bool found = false;
       string16 keyword = template_urls[i]->keyword();
-      for (size_t j = 0; j < arraysize(kFirefox3Keywords); ++j) {
+      for (size_t j = 0; j < arraysize(kFirefoxKeywords); ++j) {
         if (template_urls[i]->keyword() ==
-            WideToUTF16Hack(kFirefox3Keywords[j].keyword)) {
-          EXPECT_EQ(kFirefox3Keywords[j].url, template_urls[i]->url());
+                WideToUTF16Hack(kFirefoxKeywords[j].keyword)) {
+          EXPECT_EQ(kFirefoxKeywords[j].url, template_urls[i]->url());
           found = true;
           break;
         }
@@ -198,7 +197,7 @@
   }
 
  private:
-  virtual ~Firefox3Observer() {}
+  virtual ~FirefoxObserver() {}
 
   size_t bookmark_count_;
   size_t history_count_;
@@ -256,7 +255,7 @@
     }
 
     importer::SourceProfile source_profile;
-    source_profile.importer_type = importer::TYPE_FIREFOX3;
+    source_profile.importer_type = importer::TYPE_FIREFOX;
     source_profile.app_path = app_path_;
     source_profile.source_path = profile_path_;
     source_profile.locale = "en-US";
@@ -282,7 +281,7 @@
 
 IN_PROC_BROWSER_TEST_F(FirefoxProfileImporterBrowserTest,
                        MAYBE_IMPORTER(Firefox30Importer)) {
-  scoped_refptr<Firefox3Observer> observer(new Firefox3Observer());
+  scoped_refptr<FirefoxObserver> observer(new FirefoxObserver());
   Firefox3xImporterBrowserTest("firefox3_profile", observer.get(),
                                observer.get(), true);
 }
@@ -290,8 +289,8 @@
 IN_PROC_BROWSER_TEST_F(FirefoxProfileImporterBrowserTest,
                        MAYBE_IMPORTER(Firefox35Importer)) {
   bool import_search_engines = false;
-  scoped_refptr<Firefox3Observer> observer(
-      new Firefox3Observer(import_search_engines));
+  scoped_refptr<FirefoxObserver> observer(
+      new FirefoxObserver(import_search_engines));
   Firefox3xImporterBrowserTest("firefox35_profile", observer.get(),
                                observer.get(), import_search_engines);
 }
diff --git a/chrome/browser/importer/ie_importer_browsertest_win.cc b/chrome/browser/importer/ie_importer_browsertest_win.cc
index 79d849f..5063966 100644
--- a/chrome/browser/importer/ie_importer_browsertest_win.cc
+++ b/chrome/browser/importer/ie_importer_browsertest_win.cc
@@ -18,7 +18,7 @@
 #include "base/compiler_specific.h"
 #include "base/file_util.h"
 #include "base/files/scoped_temp_dir.h"
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "base/path_service.h"
 #include "base/stl_util.h"
 #include "base/strings/string16.h"
diff --git a/chrome/browser/importer/importer_list.cc b/chrome/browser/importer/importer_list.cc
index 0e9ff34..1863d4a 100644
--- a/chrome/browser/importer/importer_list.cc
+++ b/chrome/browser/importer/importer_list.cc
@@ -55,7 +55,7 @@
 #endif  // defined(OS_MACOSX)
 
 // |locale|: The application locale used for lookups in Firefox's
-// locale-specific search engines feature (see firefox3_importer.cc for
+// locale-specific search engines feature (see firefox_importer.cc for
 // details).
 void DetectFirefoxProfiles(const std::string locale,
                            std::vector<importer::SourceProfile*>* profiles) {
@@ -74,7 +74,7 @@
     GetFirefoxVersionAndPathFromProfile(profile_path, &version, &app_path);
 
   if (version >= 3) {
-    firefox_type = importer::TYPE_FIREFOX3;
+    firefox_type = importer::TYPE_FIREFOX;
   } else {
     // Ignores old versions of firefox.
     return;
diff --git a/chrome/browser/importer/importer_uma.cc b/chrome/browser/importer/importer_uma.cc
index 4e62217..839dd6e 100644
--- a/chrome/browser/importer/importer_uma.cc
+++ b/chrome/browser/importer/importer_uma.cc
@@ -42,7 +42,7 @@
       metrics_type = IMPORTER_METRICS_IE;
       break;
 #endif
-    case TYPE_FIREFOX3:
+    case TYPE_FIREFOX:
       metrics_type = IMPORTER_METRICS_FIREFOX3;
       break;
 #if defined(OS_MACOSX)
diff --git a/chrome/browser/importer/profile_writer_unittest.cc b/chrome/browser/importer/profile_writer_unittest.cc
index f61b6c8..2f6334b 100644
--- a/chrome/browser/importer/profile_writer_unittest.cc
+++ b/chrome/browser/importer/profile_writer_unittest.cc
@@ -4,7 +4,7 @@
 
 #include <string>
 
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/bookmarks/bookmark_model.h"
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
diff --git a/chrome/browser/infobars/infobar.cc b/chrome/browser/infobars/infobar.cc
index 079b571..2dc1391 100644
--- a/chrome/browser/infobars/infobar.cc
+++ b/chrome/browser/infobars/infobar.cc
@@ -13,25 +13,19 @@
 #include "ui/base/animation/slide_animation.h"
 
 SkColor GetInfoBarTopColor(InfoBarDelegate::Type infobar_type) {
-  // Yellow
   static const SkColor kWarningBackgroundColorTop =
-      SkColorSetRGB(255, 242, 183);
-  // Gray
+      SkColorSetRGB(255, 242, 183);  // Yellow
   static const SkColor kPageActionBackgroundColorTop =
-      SkColorSetRGB(237, 237, 237);
-
+      SkColorSetRGB(237, 237, 237);  // Gray
   return (infobar_type == InfoBarDelegate::WARNING_TYPE) ?
       kWarningBackgroundColorTop : kPageActionBackgroundColorTop;
 }
 
 SkColor GetInfoBarBottomColor(InfoBarDelegate::Type infobar_type) {
-  // Yellow
   static const SkColor kWarningBackgroundColorBottom =
-      SkColorSetRGB(250, 230, 145);
-  // Gray
+      SkColorSetRGB(250, 230, 145);  // Yellow
   static const SkColor kPageActionBackgroundColorBottom =
-      SkColorSetRGB(217, 217, 217);
-
+      SkColorSetRGB(217, 217, 217);  // Gray
   return (infobar_type == InfoBarDelegate::WARNING_TYPE) ?
       kWarningBackgroundColorBottom : kPageActionBackgroundColorBottom;
 }
diff --git a/chrome/browser/infobars/infobar_service.cc b/chrome/browser/infobars/infobar_service.cc
index f52304f..f941f22 100644
--- a/chrome/browser/infobars/infobar_service.cc
+++ b/chrome/browser/infobars/infobar_service.cc
@@ -17,23 +17,23 @@
 DEFINE_WEB_CONTENTS_USER_DATA_KEY(InfoBarService);
 
 InfoBarDelegate* InfoBarService::AddInfoBar(
-    scoped_ptr<InfoBarDelegate> delegate) {
-  DCHECK(delegate);
+    scoped_ptr<InfoBarDelegate> infobar) {
+  DCHECK(infobar);
   if (!infobars_enabled_)
     return NULL;
 
   for (InfoBars::const_iterator i(infobars_.begin()); i != infobars_.end();
        ++i) {
-    if ((*i)->EqualsDelegate(delegate.get())) {
-      DCHECK_NE(*i, delegate.get());
+    if ((*i)->EqualsDelegate(infobar.get())) {
+      DCHECK_NE(*i, infobar.get());
       return NULL;
     }
   }
 
+  InfoBarDelegate* infobar_ptr = infobar.release();
+  infobars_.push_back(infobar_ptr);
   // TODO(pkasting): Remove InfoBarService arg from delegate constructors and
   // instead use a setter from here.
-  InfoBarDelegate* delegate_ptr = delegate.release();
-  infobars_.push_back(delegate_ptr);
 
   // Add ourselves as an observer for navigations the first time a delegate is
   // added. We use this notification to expire InfoBars that need to expire on
@@ -52,40 +52,40 @@
   content::NotificationService::current()->Notify(
       chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_ADDED,
       content::Source<InfoBarService>(this),
-      content::Details<InfoBarAddedDetails>(delegate_ptr));
-  return delegate_ptr;
+      content::Details<InfoBarAddedDetails>(infobar_ptr));
+  return infobar_ptr;
 }
 
-void InfoBarService::RemoveInfoBar(InfoBarDelegate* delegate) {
-  RemoveInfoBarInternal(delegate, true);
+void InfoBarService::RemoveInfoBar(InfoBarDelegate* infobar) {
+  RemoveInfoBarInternal(infobar, true);
 }
 
 InfoBarDelegate* InfoBarService::ReplaceInfoBar(
-    InfoBarDelegate* old_delegate,
-    scoped_ptr<InfoBarDelegate> new_delegate) {
-  DCHECK(old_delegate);
+    InfoBarDelegate* old_infobar,
+    scoped_ptr<InfoBarDelegate> new_infobar) {
+  DCHECK(old_infobar);
   if (!infobars_enabled_)
-    return AddInfoBar(new_delegate.Pass());  // Deletes the delegate.
-  DCHECK(new_delegate);
+    return AddInfoBar(new_infobar.Pass());  // Deletes the delegate.
+  DCHECK(new_infobar);
 
   InfoBars::iterator i(std::find(infobars_.begin(), infobars_.end(),
-                                 old_delegate));
+                                 old_infobar));
   DCHECK(i != infobars_.end());
 
-  InfoBarDelegate* new_delegate_ptr = new_delegate.release();
-  i = infobars_.insert(i, new_delegate_ptr);
-  InfoBarReplacedDetails replaced_details(old_delegate, new_delegate_ptr);
+  InfoBarDelegate* new_infobar_ptr = new_infobar.release();
+  i = infobars_.insert(i, new_infobar_ptr);
+  InfoBarReplacedDetails replaced_details(old_infobar, new_infobar_ptr);
 
-  // Remove the old delegate before notifying, so that if any observers call
-  // back to AddInfoBar() or similar, we don't dupe-check against this delegate.
+  // Remove the old infobar before notifying, so that if any observers call
+  // back to AddInfoBar() or similar, we don't dupe-check against this infobar.
   infobars_.erase(++i);
 
-  old_delegate->clear_owner();
+  old_infobar->clear_owner();
   content::NotificationService::current()->Notify(
       chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REPLACED,
       content::Source<InfoBarService>(this),
       content::Details<InfoBarReplacedDetails>(&replaced_details));
-  return new_delegate_ptr;
+  return new_infobar_ptr;
 }
 
 InfoBarService::InfoBarService(content::WebContents* web_contents)
@@ -137,9 +137,9 @@
     // use iterators, as the RemoveInfoBar() call synchronously modifies our
     // delegate list.
     for (size_t i = infobars_.size(); i > 0; --i) {
-      InfoBarDelegate* delegate = infobars_[i - 1];
-      if (delegate->ShouldExpire(committed_details))
-        RemoveInfoBar(delegate);
+      InfoBarDelegate* infobar = infobars_[i - 1];
+      if (infobar->ShouldExpire(committed_details))
+        RemoveInfoBar(infobar);
     }
 
     return;
@@ -157,20 +157,20 @@
   return;
 }
 
-void InfoBarService::RemoveInfoBarInternal(InfoBarDelegate* delegate,
+void InfoBarService::RemoveInfoBarInternal(InfoBarDelegate* infobar,
                                            bool animate) {
-  DCHECK(delegate);
+  DCHECK(infobar);
   if (!infobars_enabled_) {
     DCHECK(infobars_.empty());
     return;
   }
 
-  InfoBars::iterator i(std::find(infobars_.begin(), infobars_.end(), delegate));
+  InfoBars::iterator i(std::find(infobars_.begin(), infobars_.end(), infobar));
   DCHECK(i != infobars_.end());
 
-  delegate->clear_owner();
-  // Remove the delegate before notifying, so that if any observers call back to
-  // AddInfoBar() or similar, we don't dupe-check against this delegate.
+  infobar->clear_owner();
+  // Remove the infobar before notifying, so that if any observers call back to
+  // AddInfoBar() or similar, we don't dupe-check against this infobar.
   infobars_.erase(i);
 
   // Remove ourselves as an observer if we are tracking no more InfoBars.  We
@@ -186,7 +186,7 @@
             &web_contents()->GetController()));
   }
 
-  InfoBarRemovedDetails removed_details(delegate, animate);
+  InfoBarRemovedDetails removed_details(infobar, animate);
   content::NotificationService::current()->Notify(
       chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED,
       content::Source<InfoBarService>(this),
diff --git a/chrome/browser/infobars/infobar_service.h b/chrome/browser/infobars/infobar_service.h
index e0f40aa..1bc98ed 100644
--- a/chrome/browser/infobars/infobar_service.h
+++ b/chrome/browser/infobars/infobar_service.h
@@ -13,10 +13,6 @@
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/browser/web_contents_user_data.h"
 
-namespace content {
-class WebContents;
-}
-
 class InfoBarDelegate;
 
 // Provides access to creating, removing and enumerating info bars
@@ -35,14 +31,14 @@
   // |delegate| is closed immediately without being added.
   //
   // Returns the delegate if it was successfully added.
-  InfoBarDelegate* AddInfoBar(scoped_ptr<InfoBarDelegate> delegate);
+  InfoBarDelegate* AddInfoBar(scoped_ptr<InfoBarDelegate> infobar);
 
   // Removes the InfoBar for the specified |delegate|.
   //
   // If infobars are disabled for this tab, this will do nothing, on the
   // assumption that the matching AddInfoBar() call will have already closed the
   // delegate (see above).
-  void RemoveInfoBar(InfoBarDelegate* delegate);
+  void RemoveInfoBar(InfoBarDelegate* infobar);
 
   // Replaces one infobar with another, without any animation in between.
   //
@@ -52,14 +48,14 @@
   // Returns the new delegate if it was successfully added.
   //
   // NOTE: This does not perform any EqualsDelegate() checks like AddInfoBar().
-  InfoBarDelegate* ReplaceInfoBar(InfoBarDelegate* old_delegate,
-                                  scoped_ptr<InfoBarDelegate> new_delegate);
+  InfoBarDelegate* ReplaceInfoBar(InfoBarDelegate* old_infobar,
+                                  scoped_ptr<InfoBarDelegate> new_infobar);
 
   // Returns the number of infobars for this tab.
   size_t infobar_count() const { return infobars_.size(); }
 
-  // Returns the infobar delegate at the given |index|.  The InfoBarService
-  // retains ownership.
+  // Returns the infobar at the given |index|.  The InfoBarService retains
+  // ownership.
   //
   // Warning: Does not sanity check |index|.
   InfoBarDelegate* infobar_at(size_t index) { return infobars_[index]; }
@@ -74,6 +70,10 @@
 
   typedef std::vector<InfoBarDelegate*> InfoBars;
 
+  // Delegates for InfoBars associated with this InfoBarService.  We do not own
+  // these pointers; they own themselves and are deleted in response to being
+  // closed.
+  // TODO(pkasting): These leak if closed while not visible.
   explicit InfoBarService(content::WebContents* web_contents);
   virtual ~InfoBarService();
 
@@ -86,14 +86,13 @@
                        const content::NotificationSource& source,
                        const content::NotificationDetails& details) OVERRIDE;
 
-  void RemoveInfoBarInternal(InfoBarDelegate* delegate, bool animate);
+  void RemoveInfoBarInternal(InfoBarDelegate* infobar, bool animate);
   void RemoveAllInfoBars(bool animate);
 
   // Message handlers.
   void OnDidBlockDisplayingInsecureContent();
   void OnDidBlockRunningInsecureContent();
 
-  // Delegates for InfoBars associated with this InfoBarService.
   InfoBars infobars_;
   bool infobars_enabled_;
 
diff --git a/chrome/browser/infobars/infobars_browsertest.cc b/chrome/browser/infobars/infobars_browsertest.cc
index f95fa56..8286b79 100644
--- a/chrome/browser/infobars/infobars_browsertest.cc
+++ b/chrome/browser/infobars/infobars_browsertest.cc
@@ -19,6 +19,10 @@
 #include "content/public/browser/notification_service.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 
+#if defined(OS_WIN) && defined(USE_ASH)
+#include "base/win/windows_version.h"
+#endif
+
 class InfoBarsTest : public InProcessBrowserTest {
  public:
   InfoBarsTest() {}
@@ -51,6 +55,12 @@
 };
 
 IN_PROC_BROWSER_TEST_F(InfoBarsTest, TestInfoBarsCloseOnNewTheme) {
+#if defined(OS_WIN) && defined(USE_ASH)
+  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
+  if (base::win::GetVersion() >= base::win::VERSION_WIN8)
+    return;
+#endif
+
   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
 
   ui_test_utils::NavigateToURL(
diff --git a/chrome/browser/infobars/insecure_content_infobar_delegate.h b/chrome/browser/infobars/insecure_content_infobar_delegate.h
index e2a78e7..f2be21a 100644
--- a/chrome/browser/infobars/insecure_content_infobar_delegate.h
+++ b/chrome/browser/infobars/insecure_content_infobar_delegate.h
@@ -18,8 +18,8 @@
 
   // Depending on the |type| requested and whether an insecure content infobar
   // is already present in |infobar_service|, may do nothing; otherwise, creates
-  // an insecure content delegate and either adds it to |infobar_service| or
-  // replaces the existing infobar delegate.
+  // an insecure content infobar delegate and either adds it to
+  // |infobar_service| or replaces the existing infobar.
   static void Create(InfoBarService* infobar_service, InfoBarType type);
 
  private:
diff --git a/chrome/browser/infobars/simple_alert_infobar_delegate.h b/chrome/browser/infobars/simple_alert_infobar_delegate.h
index 7d783f6..a5cef30 100644
--- a/chrome/browser/infobars/simple_alert_infobar_delegate.h
+++ b/chrome/browser/infobars/simple_alert_infobar_delegate.h
@@ -12,7 +12,7 @@
 
 class SimpleAlertInfoBarDelegate : public ConfirmInfoBarDelegate {
  public:
-  // Creates a simple alert delegate and adds it to |infobar_service|.
+  // Creates a simple alert infobar delegate and adds it to |infobar_service|.
   static void Create(InfoBarService* infobar_service,
                      int icon_id,  // May be |kNoIconID| if no icon is shown.
                      const string16& message,
diff --git a/chrome/browser/internal_auth_unittest.cc b/chrome/browser/internal_auth_unittest.cc
index c504bd9..415bef2 100644
--- a/chrome/browser/internal_auth_unittest.cc
+++ b/chrome/browser/internal_auth_unittest.cc
@@ -7,7 +7,7 @@
 #include <algorithm>
 
 #include "base/lazy_instance.h"
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "base/time/time.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/chrome/browser/invalidation/fake_invalidation_service.cc b/chrome/browser/invalidation/fake_invalidation_service.cc
index a54a581..a19f4fb 100644
--- a/chrome/browser/invalidation/fake_invalidation_service.cc
+++ b/chrome/browser/invalidation/fake_invalidation_service.cc
@@ -47,10 +47,12 @@
 
 void FakeInvalidationService::EmitInvalidationForTest(
       const invalidation::ObjectId& object_id,
+      int64 version,
       const std::string& payload) {
   syncer::ObjectIdInvalidationMap invalidation_map;
 
   syncer::Invalidation inv;
+  inv.version = version;
   inv.payload = payload;
   inv.ack_handle = syncer::AckHandle::CreateUnique();
 
diff --git a/chrome/browser/invalidation/fake_invalidation_service.h b/chrome/browser/invalidation/fake_invalidation_service.h
index 50aa619..4b296ae 100644
--- a/chrome/browser/invalidation/fake_invalidation_service.h
+++ b/chrome/browser/invalidation/fake_invalidation_service.h
@@ -5,6 +5,7 @@
 #ifndef CHROME_BROWSER_INVALIDATION_FAKE_INVALIDATION_SERVICE_H_
 #define CHROME_BROWSER_INVALIDATION_FAKE_INVALIDATION_SERVICE_H_
 
+#include "base/basictypes.h"
 #include "chrome/browser/invalidation/invalidation_service.h"
 #include "sync/notifier/invalidator_registrar.h"
 
@@ -34,6 +35,7 @@
 
   void EmitInvalidationForTest(
       const invalidation::ObjectId& object_id,
+      int64 version,
       const std::string& payload);
 
  private:
diff --git a/chrome/browser/invalidation/invalidation_service_android.cc b/chrome/browser/invalidation/invalidation_service_android.cc
index 06cf3e7..b12f123 100644
--- a/chrome/browser/invalidation/invalidation_service_android.cc
+++ b/chrome/browser/invalidation/invalidation_service_android.cc
@@ -72,7 +72,9 @@
   const syncer::ObjectIdInvalidationMap& effective_invalidation_map =
       object_invalidation_map.empty() ?
       ObjectIdSetToInvalidationMap(
-          invalidator_registrar_.GetAllRegisteredIds(), std::string()) :
+          invalidator_registrar_.GetAllRegisteredIds(),
+          syncer::Invalidation::kUnknownVersion,
+          std::string()) :
       object_invalidation_map;
 
   invalidator_registrar_.DispatchInvalidationsToHandlers(
diff --git a/chrome/browser/invalidation/invalidator_storage_unittest.cc b/chrome/browser/invalidation/invalidator_storage_unittest.cc
index 1bc015a..985ec94 100644
--- a/chrome/browser/invalidation/invalidator_storage_unittest.cc
+++ b/chrome/browser/invalidation/invalidator_storage_unittest.cc
@@ -5,7 +5,7 @@
 #include "chrome/browser/invalidation/invalidator_storage.h"
 
 #include "base/bind.h"
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "base/message_loop/message_loop_proxy.h"
 #include "base/prefs/pref_service.h"
 #include "base/strings/string_number_conversions.h"
diff --git a/chrome/browser/invalidation/ticl_invalidation_service.cc b/chrome/browser/invalidation/ticl_invalidation_service.cc
index f1bd4e7..ee2da37 100644
--- a/chrome/browser/invalidation/ticl_invalidation_service.cc
+++ b/chrome/browser/invalidation/ticl_invalidation_service.cc
@@ -356,6 +356,7 @@
 }
 
 void TiclInvalidationService::Logout() {
+  access_token_request_.reset();
   request_access_token_retry_timer_.Stop();
 
   if (IsStarted()) {
diff --git a/chrome/browser/io_thread.cc b/chrome/browser/io_thread.cc
index 63d5cc9..3688996 100644
--- a/chrome/browser/io_thread.cc
+++ b/chrome/browser/io_thread.cc
@@ -85,10 +85,6 @@
 #include "net/proxy/proxy_resolver_v8.h"
 #endif
 
-#if defined(OS_CHROMEOS)
-#include "chrome/browser/chromeos/proxy_config_service_impl.h"
-#endif  // defined(OS_CHROMEOS)
-
 using content::BrowserThread;
 
 class SafeBrowsingURLRequestContext;
@@ -514,7 +510,7 @@
   }
   globals_->http_auth_handler_factory.reset(CreateDefaultAuthHandlerFactory(
       globals_->host_resolver.get()));
-  globals_->http_server_properties.reset(new net::HttpServerPropertiesImpl);
+  globals_->http_server_properties.reset(new net::HttpServerPropertiesImpl());
   // For the ProxyScriptFetcher, we use a direct ProxyService.
   globals_->proxy_script_fetcher_proxy_service.reset(
       net::ProxyService::CreateDirectWithNetLog(net_log_));
@@ -862,7 +858,8 @@
   params->transport_security_state = globals_->transport_security_state.get();
   params->ssl_config_service = globals_->ssl_config_service.get();
   params->http_auth_handler_factory = globals_->http_auth_handler_factory.get();
-  params->http_server_properties = globals_->http_server_properties.get();
+  params->http_server_properties =
+      globals_->http_server_properties->GetWeakPtr();
   params->network_delegate = globals_->system_network_delegate.get();
   params->host_mapping_rules = globals_->host_mapping_rules.get();
   params->ignore_certificate_errors = globals_->ignore_certificate_errors;
@@ -914,10 +911,9 @@
   // If we're in unit_tests, IOThread may not be run.
   if (!BrowserThread::IsMessageLoopValid(BrowserThread::IO))
     return;
-  ChromeProxyConfigService* proxy_config_service =
-      ProxyServiceFactory::CreateProxyConfigService();
-  system_proxy_config_service_.reset(proxy_config_service);
-  pref_proxy_config_tracker_->SetChromeProxyConfigService(proxy_config_service);
+  system_proxy_config_service_.reset(
+      ProxyServiceFactory::CreateProxyConfigService(
+          pref_proxy_config_tracker_.get()));
   system_url_request_context_getter_ =
       new SystemURLRequestContextGetter(this);
   // Safe to post an unretained this pointer, since IOThread is
@@ -972,8 +968,7 @@
   if (command_line.HasSwitch(switches::kDisableQuic))
     return false;
 
-  if (command_line.HasSwitch(switches::kEnableQuic) ||
-      command_line.HasSwitch(switches::kEnableQuicHttps)) {
+  if (command_line.HasSwitch(switches::kEnableQuic)) {
     return true;
   }
 
diff --git a/chrome/browser/io_thread.h b/chrome/browser/io_thread.h
index eed9d17..4b1b9ef 100644
--- a/chrome/browser/io_thread.h
+++ b/chrome/browser/io_thread.h
@@ -22,7 +22,7 @@
 
 class ChromeNetLog;
 class CommandLine;
-class PrefProxyConfigTrackerImpl;
+class PrefProxyConfigTracker;
 class PrefService;
 class PrefRegistrySimple;
 class SystemURLRequestContextGetter;
@@ -300,7 +300,7 @@
   // which gets posted by calling certain member functions of IOThread.
   scoped_ptr<net::ProxyConfigService> system_proxy_config_service_;
 
-  scoped_ptr<PrefProxyConfigTrackerImpl> pref_proxy_config_tracker_;
+  scoped_ptr<PrefProxyConfigTracker> pref_proxy_config_tracker_;
 
   scoped_refptr<net::URLRequestContextGetter>
       system_url_request_context_getter_;
diff --git a/chrome/browser/jankometer.cc b/chrome/browser/jankometer.cc
index 5fa82c3..4cfbc41 100644
--- a/chrome/browser/jankometer.cc
+++ b/chrome/browser/jankometer.cc
@@ -10,7 +10,7 @@
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/memory/ref_counted.h"
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "base/metrics/histogram.h"
 #include "base/metrics/stats_counters.h"
 #include "base/pending_task.h"
diff --git a/chrome/browser/lifetime/application_lifetime.cc b/chrome/browser/lifetime/application_lifetime.cc
index c594d8e..0b67716 100644
--- a/chrome/browser/lifetime/application_lifetime.cc
+++ b/chrome/browser/lifetime/application_lifetime.cc
@@ -8,7 +8,7 @@
 #include "base/command_line.h"
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "base/prefs/pref_service.h"
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
diff --git a/chrome/browser/local_discovery/privet_constants.cc b/chrome/browser/local_discovery/privet_constants.cc
index d9c3d9f..3998576 100644
--- a/chrome/browser/local_discovery/privet_constants.cc
+++ b/chrome/browser/local_discovery/privet_constants.cc
@@ -21,6 +21,8 @@
 const char kPrivetActionGetClaimToken[] = "getClaimToken";
 const char kPrivetActionComplete[] = "complete";
 
+const char kPrivetActionNameInfo[] = "info";
+
 extern const char kPrivetDefaultDeviceType[] = "_privet._tcp.local";
 extern const char kPrivetSubtypeTemplate[] = "%s._sub._privet._tcp.local";
 
diff --git a/chrome/browser/local_discovery/privet_constants.h b/chrome/browser/local_discovery/privet_constants.h
index 4c8465d..e1b5971 100644
--- a/chrome/browser/local_discovery/privet_constants.h
+++ b/chrome/browser/local_discovery/privet_constants.h
@@ -22,6 +22,9 @@
 extern const char kPrivetActionGetClaimToken[];
 extern const char kPrivetActionComplete[];
 
+// Name for pseudo-action "info", used only to show info stage in errors.
+extern const char kPrivetActionNameInfo[];
+
 extern const char kPrivetDefaultDeviceType[];
 extern const char kPrivetSubtypeTemplate[];
 
diff --git a/chrome/browser/local_discovery/privet_http_impl.cc b/chrome/browser/local_discovery/privet_http_impl.cc
index 6c781f1..38eacd7 100644
--- a/chrome/browser/local_discovery/privet_http_impl.cc
+++ b/chrome/browser/local_discovery/privet_http_impl.cc
@@ -5,7 +5,7 @@
 #include "chrome/browser/local_discovery/privet_http_impl.h"
 
 #include "base/bind.h"
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "base/rand_util.h"
 #include "base/strings/stringprintf.h"
 #include "chrome/browser/local_discovery/privet_constants.h"
@@ -215,16 +215,26 @@
 void PrivetRegisterOperationImpl::OnPrivetInfoDone(
     int http_code,
     const base::DictionaryValue* value) {
+  // TODO(noamsml): Distinguish between network errors and unparsable JSON in
+  // this case.
+  if (!value) {
+    delegate_->OnPrivetRegisterError(kPrivetActionNameInfo,
+                                     FAILURE_NETWORK,
+                                     -1,
+                                     NULL);
+    return;
+  }
+
   // If there is a key in the info response, the InfoOperation
   // has stored it in the client.
-  if (!value || !value->HasKey(kPrivetInfoKeyToken)) {
+  if (!value->HasKey(kPrivetInfoKeyToken)) {
     if (value->HasKey(kPrivetKeyError)) {
-      delegate_->OnPrivetRegisterError(current_action_,
+      delegate_->OnPrivetRegisterError(kPrivetActionNameInfo,
                                        FAILURE_JSON_ERROR,
                                        http_code,
                                        value);
     } else {
-      delegate_->OnPrivetRegisterError(current_action_,
+      delegate_->OnPrivetRegisterError(kPrivetActionNameInfo,
                                        FAILURE_MALFORMED_RESPONSE,
                                        -1,
                                        NULL);
diff --git a/chrome/browser/local_discovery/privet_http_unittest.cc b/chrome/browser/local_discovery/privet_http_unittest.cc
index 97d28e5..05cf2c5 100644
--- a/chrome/browser/local_discovery/privet_http_unittest.cc
+++ b/chrome/browser/local_discovery/privet_http_unittest.cc
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 #include "base/bind.h"
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "chrome/browser/local_discovery/privet_http_impl.h"
 #include "net/base/host_port_pair.h"
 #include "net/base/net_errors.h"
@@ -73,6 +73,8 @@
 const char kSampleRegisterErrorPermanent[] =
     "{ \"error\": \"user_cancel\" }";
 
+const char kSampleInfoResponseBadJson[] = "{";
+
 class MockTestURLFetcherFactoryDelegate
     : public net::TestURLFetcher::DelegateForTests {
  public:
@@ -400,7 +402,7 @@
 }
 
 TEST_F(PrivetRegisterTest, PermanentFailure) {
-    register_operation_->Start();
+  register_operation_->Start();
 
   EXPECT_TRUE(SuccessfulResponseToURL(
       GURL("http://10.0.0.8:6006/privet/info"),
@@ -423,6 +425,21 @@
       kSampleRegisterErrorPermanent));
 }
 
+TEST_F(PrivetRegisterTest, InfoFailure) {
+  register_operation_->Start();
+
+  EXPECT_CALL(register_delegate_,
+              OnPrivetRegisterErrorInternal(
+                  "info",
+                  PrivetRegisterOperation::FAILURE_NETWORK,
+                  -1));
+
+
+  EXPECT_TRUE(SuccessfulResponseToURL(
+      GURL("http://10.0.0.8:6006/privet/info"),
+      kSampleInfoResponseBadJson));
+}
+
 }  // namespace
 
 }  // namespace local_discovery
diff --git a/chrome/browser/local_discovery/privet_url_fetcher.cc b/chrome/browser/local_discovery/privet_url_fetcher.cc
index d0a74b5..52da787 100644
--- a/chrome/browser/local_discovery/privet_url_fetcher.cc
+++ b/chrome/browser/local_discovery/privet_url_fetcher.cc
@@ -27,6 +27,10 @@
   url_fetcher_->SetRequestContext(request_context);
   url_fetcher_->AddExtraRequestHeader(std::string(kXPrivetTokenHeaderPrefix) +
                                       token);
+
+  // URLFetcher requires us to set upload data for POST requests.
+  if (request_type == net::URLFetcher::POST)
+      url_fetcher_->SetUploadData(std::string(), std::string());
 }
 
 PrivetURLFetcher::~PrivetURLFetcher() {
diff --git a/chrome/browser/local_discovery/service_discovery_host_client.cc b/chrome/browser/local_discovery/service_discovery_host_client.cc
new file mode 100644
index 0000000..42b5a22
--- /dev/null
+++ b/chrome/browser/local_discovery/service_discovery_host_client.cc
@@ -0,0 +1,241 @@
+// Copyright 2013 The Chromium Authors. 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_host_client.h"
+
+#include "chrome/common/local_discovery/local_discovery_messages.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/utility_process_host.h"
+
+namespace local_discovery {
+
+using content::BrowserThread;
+using content::UtilityProcessHost;
+
+class ServiceDiscoveryHostClient::ServiceWatcherProxy : public ServiceWatcher {
+ public:
+  ServiceWatcherProxy(ServiceDiscoveryHostClient* host,
+                      const std::string& service_type,
+                      const ServiceWatcher::UpdatedCallback& callback)
+      : host_(host),
+        service_type_(service_type),
+        id_(host_->RegisterWatcherCallback(callback)),
+        started_(false) {
+  }
+
+  virtual ~ServiceWatcherProxy() {
+    host_->UnregisterWatcherCallback(id_);
+    if (started_)
+      host_->Send(new LocalDiscoveryMsg_DestroyWatcher(id_));
+  }
+
+  virtual void Start() OVERRIDE {
+    DCHECK(!started_);
+    host_->Send(new LocalDiscoveryMsg_StartWatcher(id_, service_type_));
+    started_ = true;
+  }
+
+  virtual void DiscoverNewServices(bool force_update) OVERRIDE {
+    DCHECK(started_);
+    host_->Send(new LocalDiscoveryMsg_DiscoverServices(id_, force_update));
+  }
+
+  virtual std::string GetServiceType() const OVERRIDE {
+    return service_type_;
+  }
+
+ private:
+  scoped_refptr<ServiceDiscoveryHostClient> host_;
+  const std::string service_type_;
+  const uint64 id_;
+  bool started_;
+};
+
+class ServiceDiscoveryHostClient::ServiceResolverProxy
+    : public ServiceResolver {
+ public:
+  ServiceResolverProxy(ServiceDiscoveryHostClient* host,
+                       const std::string& service_name,
+                       const ServiceResolver::ResolveCompleteCallback& callback)
+      : host_(host),
+        service_name_(service_name),
+        id_(host->RegisterResolverCallback(callback)),
+        started_(false) {
+  }
+
+  virtual ~ServiceResolverProxy() {
+    host_->UnregisterResolverCallback(id_);
+    if (started_)
+      host_->Send(new LocalDiscoveryMsg_DestroyResolver(id_));
+  }
+
+  virtual void StartResolving() OVERRIDE {
+    DCHECK(!started_);
+    host_->Send(new LocalDiscoveryMsg_ResolveService(id_, service_name_));
+    started_ = true;
+  }
+
+  virtual std::string GetName() const OVERRIDE {
+    return service_name_;
+  }
+
+ private:
+  scoped_refptr<ServiceDiscoveryHostClient> host_;
+  const std::string service_name_;
+  const uint64 id_;
+  bool started_;
+};
+
+ServiceDiscoveryHostClient::ServiceDiscoveryHostClient() : current_id_(0) {
+  callback_runner_ = base::MessageLoop::current()->message_loop_proxy();
+}
+
+ServiceDiscoveryHostClient::~ServiceDiscoveryHostClient() {
+  DCHECK(CalledOnValidThread());
+  DCHECK(service_watcher_callbacks_.empty());
+  DCHECK(service_resolver_callbacks_.empty());
+}
+
+scoped_ptr<ServiceWatcher> ServiceDiscoveryHostClient::CreateServiceWatcher(
+    const std::string& service_type,
+    const ServiceWatcher::UpdatedCallback& callback) {
+  DCHECK(CalledOnValidThread());
+  return scoped_ptr<ServiceWatcher>(
+      new ServiceWatcherProxy(this, service_type, callback));
+}
+
+scoped_ptr<ServiceResolver> ServiceDiscoveryHostClient::CreateServiceResolver(
+    const std::string& service_name,
+    const ServiceResolver::ResolveCompleteCallback& callback) {
+  DCHECK(CalledOnValidThread());
+  return scoped_ptr<ServiceResolver>(
+      new ServiceResolverProxy(this, service_name, callback));
+}
+
+uint64 ServiceDiscoveryHostClient::RegisterWatcherCallback(
+    const ServiceWatcher::UpdatedCallback& callback) {
+  DCHECK(CalledOnValidThread());
+  DCHECK(!ContainsKey(service_watcher_callbacks_, current_id_ + 1));
+  service_watcher_callbacks_[++current_id_] = callback;
+  return current_id_;
+}
+
+uint64 ServiceDiscoveryHostClient::RegisterResolverCallback(
+    const ServiceResolver::ResolveCompleteCallback& callback) {
+  DCHECK(CalledOnValidThread());
+  DCHECK(!ContainsKey(service_resolver_callbacks_, current_id_ + 1));
+  service_resolver_callbacks_[++current_id_] = callback;
+  return current_id_;
+}
+
+void ServiceDiscoveryHostClient::UnregisterWatcherCallback(uint64 id) {
+  DCHECK(CalledOnValidThread());
+  DCHECK(ContainsKey(service_watcher_callbacks_, id));
+  service_watcher_callbacks_.erase(id);
+}
+
+void ServiceDiscoveryHostClient::UnregisterResolverCallback(uint64 id) {
+  DCHECK(CalledOnValidThread());
+  DCHECK(ContainsKey(service_resolver_callbacks_, id));
+  service_resolver_callbacks_.erase(id);
+}
+
+void ServiceDiscoveryHostClient::Start() {
+  DCHECK(CalledOnValidThread());
+  BrowserThread::PostTask(
+      BrowserThread::IO,
+      FROM_HERE,
+      base::Bind(&ServiceDiscoveryHostClient::StartOnIOThread, this));
+}
+
+void ServiceDiscoveryHostClient::Shutdown() {
+  DCHECK(CalledOnValidThread());
+  BrowserThread::PostTask(
+      BrowserThread::IO,
+      FROM_HERE,
+      base::Bind(&ServiceDiscoveryHostClient::ShutdownOnIOThread, this));
+}
+
+void ServiceDiscoveryHostClient::StartOnIOThread() {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+  utility_host_ = UtilityProcessHost::Create(
+      this, base::MessageLoopProxy::current().get())->AsWeakPtr();
+  if (utility_host_) {
+    utility_host_->EnableZygote();
+    utility_host_->EnableMDns();
+    utility_host_->StartBatchMode();
+  }
+}
+
+void ServiceDiscoveryHostClient::ShutdownOnIOThread() {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+  if (utility_host_)
+    utility_host_->EndBatchMode();
+}
+
+void ServiceDiscoveryHostClient::Send(IPC::Message* msg) {
+  DCHECK(CalledOnValidThread());
+  BrowserThread::PostTask(
+      BrowserThread::IO,
+      FROM_HERE,
+      base::Bind(base::IgnoreResult(&content::UtilityProcessHost::Send),
+                 utility_host_, msg));
+}
+
+bool ServiceDiscoveryHostClient::OnMessageReceived(
+    const IPC::Message& message) {
+  bool handled = true;
+  IPC_BEGIN_MESSAGE_MAP(ServiceDiscoveryHostClient, message)
+    IPC_MESSAGE_HANDLER(LocalDiscoveryHostMsg_WatcherCallback,
+                        OnWatcherCallback)
+    IPC_MESSAGE_HANDLER(LocalDiscoveryHostMsg_ResolverCallback,
+                        OnResolverCallback)
+    IPC_MESSAGE_UNHANDLED(handled = false)
+  IPC_END_MESSAGE_MAP()
+  return handled;
+}
+
+void ServiceDiscoveryHostClient::OnWatcherCallback(
+    uint64 id,
+    ServiceWatcher::UpdateType update,
+    const std::string& service_name) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+  callback_runner_->PostTask(
+      FROM_HERE,
+      base::Bind(&ServiceDiscoveryHostClient::RunWatcherCallback, this, id,
+                 update, service_name));
+}
+
+void ServiceDiscoveryHostClient::OnResolverCallback(
+    uint64 id,
+    ServiceResolver::RequestStatus status,
+    const ServiceDescription& description) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+  callback_runner_->PostTask(
+      FROM_HERE,
+      base::Bind(&ServiceDiscoveryHostClient::RunResolverCallback, this, id,
+                 status, description));
+}
+
+void ServiceDiscoveryHostClient::RunWatcherCallback(
+    uint64 id,
+    ServiceWatcher::UpdateType update,
+    const std::string& service_name) {
+  DCHECK(CalledOnValidThread());
+  WatcherCallbacks::iterator it = service_watcher_callbacks_.find(id);
+  if (it != service_watcher_callbacks_.end() && !it->second.is_null())
+    it->second.Run(update, service_name);
+}
+
+void ServiceDiscoveryHostClient::RunResolverCallback(
+    uint64 id,
+    ServiceResolver::RequestStatus status,
+    const ServiceDescription& description) {
+  DCHECK(CalledOnValidThread());
+  ResolverCallbacks::iterator it = service_resolver_callbacks_.find(id);
+  if (it != service_resolver_callbacks_.end() && !it->second.is_null())
+    it->second.Run(status, description);
+}
+
+}  // namespace local_discovery
diff --git a/chrome/browser/local_discovery/service_discovery_host_client.h b/chrome/browser/local_discovery/service_discovery_host_client.h
new file mode 100644
index 0000000..4bdf08b
--- /dev/null
+++ b/chrome/browser/local_discovery/service_discovery_host_client.h
@@ -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.
+
+#ifndef CHROME_BROWSER_LOCAL_DISCOVERY_SERVICE_DISCOVERY_HOST_CLIENT_H_
+#define CHROME_BROWSER_LOCAL_DISCOVERY_SERVICE_DISCOVERY_HOST_CLIENT_H_
+
+#include <map>
+
+#include "base/threading/non_thread_safe.h"
+#include "chrome/common/local_discovery/service_discovery_client.h"
+#include "content/public/browser/utility_process_host_client.h"
+
+namespace base {
+class TaskRunner;
+}
+
+namespace content {
+class UtilityProcessHost;
+}
+
+namespace local_discovery {
+
+// Implementation of ServiceDiscoveryClient that delegates all functionality to
+// utility process.
+class ServiceDiscoveryHostClient : public base::NonThreadSafe,
+                                   public ServiceDiscoveryClient,
+                                   public content::UtilityProcessHostClient {
+ public:
+  ServiceDiscoveryHostClient();
+
+  // Starts utility process with ServiceDiscoveryClient.
+  void Start();
+
+  // Shutdowns utility process.
+  void Shutdown();
+
+  // ServiceDiscoveryClient implementation.
+  virtual scoped_ptr<ServiceWatcher> CreateServiceWatcher(
+      const std::string& service_type,
+      const ServiceWatcher::UpdatedCallback& callback) OVERRIDE;
+  virtual scoped_ptr<ServiceResolver> CreateServiceResolver(
+      const std::string& service_name,
+      const ServiceResolver::ResolveCompleteCallback& callback) OVERRIDE;
+
+  // UtilityProcessHostClient implementation.
+  virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+
+ protected:
+  virtual ~ServiceDiscoveryHostClient();
+
+ private:
+  class ServiceWatcherProxy;
+  class ServiceResolverProxy;
+
+  typedef std::map<uint64, ServiceWatcher::UpdatedCallback> WatcherCallbacks;
+  typedef std::map<uint64, ServiceResolver::ResolveCompleteCallback>
+      ResolverCallbacks;
+
+  void StartOnIOThread();
+  void ShutdownOnIOThread();
+
+  void Send(IPC::Message* msg);
+
+  uint64 RegisterWatcherCallback(
+      const ServiceWatcher::UpdatedCallback& callback);
+  uint64 RegisterResolverCallback(
+      const ServiceResolver::ResolveCompleteCallback& callback);
+  void UnregisterWatcherCallback(uint64 id);
+  void UnregisterResolverCallback(uint64 id);
+
+  // IPC Message handlers.
+  void OnWatcherCallback(uint64 id,
+                         ServiceWatcher::UpdateType update,
+                         const std::string& service_name);
+  void OnResolverCallback(uint64 id,
+                          ServiceResolver::RequestStatus status,
+                          const ServiceDescription& description);
+
+  // Runs watcher callback on owning thread.
+  void RunWatcherCallback(uint64 id,
+                          ServiceWatcher::UpdateType update,
+                          const std::string& service_name);
+  // Runs resolver callback on owning thread.
+  void RunResolverCallback(uint64 id,
+                           ServiceResolver::RequestStatus status,
+                           const ServiceDescription& description);
+
+  base::WeakPtr<content::UtilityProcessHost> utility_host_;
+
+  // Incrementing counter to assign ID to watchers and resolvers.
+  uint64 current_id_;
+  WatcherCallbacks service_watcher_callbacks_;
+  ResolverCallbacks service_resolver_callbacks_;
+  scoped_refptr<base::TaskRunner> callback_runner_;
+
+  DISALLOW_COPY_AND_ASSIGN(ServiceDiscoveryHostClient);
+};
+
+}  // namespace local_discovery
+
+#endif  // CHROME_BROWSER_LOCAL_DISCOVERY_SERVICE_DISCOVERY_HOST_CLIENT_H_
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 4eaa308..419f6b1 100644
--- a/chrome/browser/managed_mode/managed_mode_url_filter_unittest.cc
+++ b/chrome/browser/managed_mode/managed_mode_url_filter_unittest.cc
@@ -4,7 +4,7 @@
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "chrome/browser/managed_mode/managed_mode_url_filter.h"
 #include "testing/gtest/include/gtest/gtest.h"
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 424ed86..7b7bebf 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
@@ -4,7 +4,7 @@
 
 #include "base/bind.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/managed_mode/managed_user_refresh_token_fetcher.h"
@@ -81,6 +81,9 @@
      const OAuth2TokenService::ScopeSet& scopes,
       OAuth2TokenService::Consumer* consumer) OVERRIDE;
   virtual std::string GetRefreshToken() OVERRIDE;
+  virtual net::URLRequestContextGetter* GetRequestContext() OVERRIDE {
+    return NULL;
+  }
 
   Request* request_;
 
@@ -110,9 +113,7 @@
   consumer_->OnGetTokenFailure(this, GoogleServiceAuthError(error));
 }
 
-MockOAuth2TokenService::MockOAuth2TokenService()
-    : OAuth2TokenService(NULL),
-      request_(NULL) {}
+MockOAuth2TokenService::MockOAuth2TokenService() : request_(NULL) {}
 
 MockOAuth2TokenService::~MockOAuth2TokenService() {
   EXPECT_FALSE(request_);
diff --git a/chrome/browser/managed_mode/managed_user_registration_service_unittest.cc b/chrome/browser/managed_mode/managed_user_registration_service_unittest.cc
index ef188c5..60e4a35 100644
--- a/chrome/browser/managed_mode/managed_user_registration_service_unittest.cc
+++ b/chrome/browser/managed_mode/managed_user_registration_service_unittest.cc
@@ -5,7 +5,7 @@
 #include <string>
 
 #include "base/bind.h"
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/sequenced_worker_pool.h"
diff --git a/chrome/browser/media/audio_stream_indicator.cc b/chrome/browser/media/audio_stream_indicator.cc
index 6cd6232..1d3aa72 100644
--- a/chrome/browser/media/audio_stream_indicator.cc
+++ b/chrome/browser/media/audio_stream_indicator.cc
@@ -4,6 +4,8 @@
 
 #include "chrome/browser/media/audio_stream_indicator.h"
 
+#include <limits>
+
 #include "base/bind.h"
 #include "chrome/browser/tab_contents/tab_util.h"
 #include "content/public/browser/browser_thread.h"
@@ -20,58 +22,106 @@
 
 void AudioStreamIndicator::UpdateWebContentsStatus(
     int render_process_id, int render_view_id, int stream_id,
-    bool is_playing_and_audible) {
+    bool is_playing, float power_dbfs, bool clipped) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
 
   BrowserThread::PostTask(
       BrowserThread::UI, FROM_HERE,
       base::Bind(&AudioStreamIndicator::UpdateWebContentsStatusOnUIThread, this,
                  render_process_id, render_view_id, stream_id,
-                 is_playing_and_audible));
+                 is_playing, power_dbfs, clipped));
 }
 
-bool AudioStreamIndicator::IsPlayingAudio(WebContents* contents) {
+bool AudioStreamIndicator::IsPlayingAudio(const WebContents* contents) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 
-  RenderViewId id(contents->GetRenderProcessHost()->GetID(),
-                  contents->GetRenderViewHost()->GetRoutingID());
-  return audio_streams_.find(id) != audio_streams_.end();
+  // TODO(miu): In order to prevent breaking existing uses of this method, the
+  // old semantics of "playing AND not silent" have been retained here.  Once
+  // the tab audio indicator UI switches over to using the new
+  // GetAudioSignalPower(), this method should really be just "playing."
+  float level;
+  bool ignored;
+  CurrentAudibleLevel(contents, &level, &ignored);
+  return level > 0.0f;
 }
 
-AudioStreamIndicator::RenderViewId::RenderViewId(int render_process_id,
-                                                 int render_view_id)
-    : render_process_id(render_process_id),
-      render_view_id(render_view_id) {
-}
+void AudioStreamIndicator::CurrentAudibleLevel(
+    const content::WebContents* contents, float* level, bool* clipped) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 
-bool AudioStreamIndicator::RenderViewId::operator<(
-    const RenderViewId& other) const {
-  if (render_process_id != other.render_process_id)
-    return render_process_id < other.render_process_id;
+  float max_power_dbfs = -std::numeric_limits<float>::infinity();
+  bool has_clipped = false;
 
-  return render_view_id < other.render_view_id;
+  // Since a RenderView can have more than one stream playing back, return the
+  // maximum of the last-reported power levels.  For more information about how
+  // the power level is measured, see media/audio/audio_power_monitor.h.
+  const RenderViewId id(contents->GetRenderProcessHost()->GetID(),
+                        contents->GetRenderViewHost()->GetRoutingID());
+  RenderViewStreamMap::const_iterator view_it = audio_streams_.find(id);
+  if (view_it != audio_streams_.end()) {
+    const StreamPowerLevels& stream_levels = view_it->second;
+    for (StreamPowerLevels::const_iterator stream_it = stream_levels.begin();
+         stream_it != stream_levels.end(); ++stream_it) {
+      if (stream_it->power_dbfs > max_power_dbfs)
+        max_power_dbfs = stream_it->power_dbfs;
+      has_clipped |= stream_it->clipped;
+    }
+  }
+
+  // Map the power into an "audible level" in the range [0.0,1.0].  dBFS values
+  // are in the range -inf (minimum power) to 0.0 (maximum power).
+  static const float kSilenceThresholdDBFS = -72.24719896f;
+  if (max_power_dbfs < kSilenceThresholdDBFS)
+    *level = 0.0f;
+  else if (max_power_dbfs > 0.0f)
+    *level = 1.0f;
+  else
+    *level = 1.0f - max_power_dbfs / kSilenceThresholdDBFS;
+  *clipped = has_clipped;
 }
 
 void AudioStreamIndicator::UpdateWebContentsStatusOnUIThread(
-    int render_process_id,
-    int render_view_id,
-    int stream_id,
-    bool is_playing_and_audible) {
+    int render_process_id, int render_view_id, int stream_id,
+    bool is_playing, float power_dbfs, bool clipped) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  RenderViewId id(render_process_id, render_view_id);
-  if (is_playing_and_audible) {
-    audio_streams_[id].insert(stream_id);
-  } else {
-    std::map<RenderViewId, std::set<int> >::iterator it =
-        audio_streams_.find(id);
-    if (it == audio_streams_.end())
-      return;
 
-    it->second.erase(stream_id);
-    if (it->second.empty())
-      audio_streams_.erase(it);
+  const RenderViewId id(render_process_id, render_view_id);
+  if (is_playing) {
+    // Find the StreamPowerLevel instance associated with |stream_id|, or
+    // auto-create a new one.
+    StreamPowerLevels& stream_levels = audio_streams_[id];
+    StreamPowerLevels::iterator stream_it;
+    for (stream_it = stream_levels.begin(); stream_it != stream_levels.end();
+         ++stream_it) {
+      if (stream_it->stream_id == stream_id)
+        break;
+    }
+    if (stream_it == stream_levels.end()) {
+      stream_it = stream_levels.insert(stream_levels.end(), StreamPowerLevel());
+      stream_it->stream_id = stream_id;
+    }
+
+    // Update power and clip values.
+    stream_it->power_dbfs = power_dbfs;
+    stream_it->clipped = clipped;
+  } else {
+    // Find and erase the StreamPowerLevel instance associated with |stream_id|.
+    RenderViewStreamMap::iterator view_it = audio_streams_.find(id);
+    if (view_it != audio_streams_.end()) {
+      StreamPowerLevels& stream_levels = view_it->second;
+      for (StreamPowerLevels::iterator stream_it = stream_levels.begin();
+           stream_it != stream_levels.end(); ++stream_it) {
+        if (stream_it->stream_id == stream_id) {
+          stream_levels.erase(stream_it);
+          if (stream_levels.empty())
+            audio_streams_.erase(view_it);
+          break;
+        }
+      }
+    }
   }
 
+  // Trigger UI update.
   WebContents* web_contents = tab_util::GetWebContentsByID(render_process_id,
                                                            render_view_id);
   if (web_contents)
diff --git a/chrome/browser/media/audio_stream_indicator.h b/chrome/browser/media/audio_stream_indicator.h
index 2ce504e..613dc3c 100644
--- a/chrome/browser/media/audio_stream_indicator.h
+++ b/chrome/browser/media/audio_stream_indicator.h
@@ -6,7 +6,7 @@
 #define CHROME_BROWSER_MEDIA_AUDIO_STREAM_INDICATOR_H_
 
 #include <map>
-#include <set>
+#include <vector>
 
 #include "base/memory/ref_counted.h"
 
@@ -23,22 +23,34 @@
   void UpdateWebContentsStatus(int render_process_id,
                                int render_view_id,
                                int stream_id,
-                               bool is_playing_and_audible);
+                               bool is_playing,
+                               float power_dbfs,
+                               bool clipped);
 
   // This method should be called on the UI thread.
-  bool IsPlayingAudio(content::WebContents* contents);
+  bool IsPlayingAudio(const content::WebContents* contents);
+
+  // Returns the audible |level| in the range [0.0,1.0], where 0.0 means the
+  // audio signal is imperceivably silent and 1.0 means it is at maximum
+  // volume.  |signal_has_clipped| is set to true if any part of the audio
+  // signal has clipped since the last call to this method.
+  //
+  // This method should be called on the UI thread.
+  void CurrentAudibleLevel(const content::WebContents* contents,
+                           float* level, bool* signal_has_clipped);
 
  private:
-  struct RenderViewId {
-    RenderViewId(int render_process_id,
-                 int render_view_id);
-
-    // Required to use this struct in the std::multiset below.
-    bool operator<(const RenderViewId& other) const;
-
-    int render_process_id;
-    int render_view_id;
+  // <render process ID, render view ID>
+  // Note: Using std::pair<> to reduce binary-size bloat.
+  typedef std::pair<int, int> RenderViewId;
+  struct StreamPowerLevel {
+    int stream_id;
+    float power_dbfs;
+    bool clipped;
   };
+  typedef std::vector<StreamPowerLevel> StreamPowerLevels;
+  // Container for the power levels of streams playing from each render view.
+  typedef std::map<RenderViewId, StreamPowerLevels> RenderViewStreamMap;
 
   friend class base::RefCountedThreadSafe<AudioStreamIndicator>;
   virtual ~AudioStreamIndicator();
@@ -46,11 +58,11 @@
   void UpdateWebContentsStatusOnUIThread(int render_process_id,
                                          int render_view_id,
                                          int stream_id,
-                                         bool playing);
+                                         bool is_playing,
+                                         float power_dbfs,
+                                         bool clipped);
 
-  // A map from RenderViews to sets of streams playing in them (each RenderView
-  // might have more than one stream).
-  std::map<RenderViewId, std::set<int> > audio_streams_;
+  RenderViewStreamMap audio_streams_;
 };
 
 #endif  // CHROME_BROWSER_MEDIA_AUDIO_STREAM_INDICATOR_H_
diff --git a/chrome/browser/media/chrome_media_stream_infobar_browsertest.cc b/chrome/browser/media/chrome_media_stream_infobar_browsertest.cc
index 24410c2..5396b11 100644
--- a/chrome/browser/media/chrome_media_stream_infobar_browsertest.cc
+++ b/chrome/browser/media/chrome_media_stream_infobar_browsertest.cc
@@ -26,6 +26,10 @@
 #include "content/public/test/browser_test_utils.h"
 #include "net/test/spawned_test_server/spawned_test_server.h"
 
+#if defined(OS_WIN) && defined(USE_ASH)
+#include "base/win/windows_version.h"
+#endif
+
 static const char kMainWebrtcTestHtmlPage[] =
     "files/webrtc/webrtc_jsep01_test.html";
 static const char kFailedWithErrorPermissionDenied[] =
@@ -202,6 +206,12 @@
 
 IN_PROC_BROWSER_TEST_F(MediaStreamInfobarTest,
                        TestAcceptThenDenyWhichShouldBeSticky) {
+#if defined(OS_WIN) && defined(USE_ASH)
+  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
+  if (base::win::GetVersion() >= base::win::VERSION_WIN8)
+    return;
+#endif
+
   content::WebContents* tab_contents = LoadTestPageInTab();
 
   TestAcceptOnInfobar(tab_contents);
diff --git a/chrome/browser/media/media_capture_devices_dispatcher.cc b/chrome/browser/media/media_capture_devices_dispatcher.cc
index 6d49f98..ff9418c 100644
--- a/chrome/browser/media/media_capture_devices_dispatcher.cc
+++ b/chrome/browser/media/media_capture_devices_dispatcher.cc
@@ -64,7 +64,8 @@
       origin.spec() == "https://plus.google.com/" ||
       origin.spec() == "chrome-extension://pkedcjkdefgpdelpbcmbmeomcjbeemfm/" ||
       origin.spec() == "chrome-extension://fmfcbgogabcbclcofgocippekhfcmgfj/" ||
-      origin.spec() == "chrome-extension://hfaagokkkhdbgiakmmlclaapfelnkoah/") {
+      origin.spec() == "chrome-extension://hfaagokkkhdbgiakmmlclaapfelnkoah/" ||
+      origin.spec() == "chrome-extension://gfdkimpbcpahaombhbimeihdjnejgicl/") {
     return true;
   }
   // Check against hashed origins.
@@ -175,7 +176,9 @@
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 
   if (request.video_type == content::MEDIA_SCREEN_VIDEO_CAPTURE) {
-    ProcessScreenCaptureAccessRequest(web_contents, request, callback);
+    ProcessScreenCaptureAccessRequest(
+        web_contents, request, callback,
+        extension && extension->location() == extensions::Manifest::COMPONENT);
   } else if (extension) {
     // For extensions access is approved based on extension permissions.
     ProcessMediaAccessRequestFromExtension(
@@ -188,7 +191,8 @@
 void MediaCaptureDevicesDispatcher::ProcessScreenCaptureAccessRequest(
     content::WebContents* web_contents,
     const content::MediaStreamRequest& request,
-    const content::MediaResponseCallback& callback) {
+    const content::MediaResponseCallback& callback,
+    bool component_extension) {
   content::MediaStreamDevices devices;
 
   bool screen_capture_enabled =
@@ -209,22 +213,30 @@
   //  3. Audio capture was not requested (it's not supported yet).
   if (screen_capture_enabled && origin_is_secure &&
       request.audio_type == content::MEDIA_NO_SERVICE) {
-    string16 application_name = UTF8ToUTF16(request.security_origin.spec());
-    chrome::MessageBoxResult result = chrome::ShowMessageBox(
-        NULL,
-        l10n_util::GetStringFUTF16(IDS_MEDIA_SCREEN_CAPTURE_CONFIRMATION_TITLE,
-                                   application_name),
-        l10n_util::GetStringFUTF16(IDS_MEDIA_SCREEN_CAPTURE_CONFIRMATION_TEXT,
-                                   application_name),
-        chrome::MESSAGE_BOX_TYPE_QUESTION);
-    if (result == chrome::MESSAGE_BOX_RESULT_YES) {
+    // For component extensions, bypass message box.
+    bool user_approved = false;
+    if (!component_extension) {
+      string16 application_name = UTF8ToUTF16(request.security_origin.spec());
+      chrome::MessageBoxResult result = chrome::ShowMessageBox(
+          NULL,
+          l10n_util::GetStringFUTF16(
+              IDS_MEDIA_SCREEN_CAPTURE_CONFIRMATION_TITLE, application_name),
+          l10n_util::GetStringFUTF16(
+              IDS_MEDIA_SCREEN_CAPTURE_CONFIRMATION_TEXT, application_name),
+          chrome::MESSAGE_BOX_TYPE_QUESTION);
+      user_approved = (result == chrome::MESSAGE_BOX_RESULT_YES);
+    }
+
+    if (user_approved || component_extension) {
       devices.push_back(content::MediaStreamDevice(
           content::MEDIA_SCREEN_VIDEO_CAPTURE, std::string(), "Screen"));
     }
   }
 
   scoped_ptr<content::MediaStreamUI> ui;
-  if (!devices.empty()) {
+  // Unless we're being invoked from a component extension, register to display
+  // the notification for stream capture.
+  if (!devices.empty() && !component_extension) {
     ui = media_stream_capture_indicator_->RegisterMediaStream(
         web_contents, devices);
   }
@@ -468,11 +480,21 @@
 
 void MediaCaptureDevicesDispatcher::OnAudioStreamPlayingChanged(
     int render_process_id, int render_view_id, int stream_id,
-    bool is_playing_and_audible) {
-  audio_stream_indicator_->UpdateWebContentsStatus(render_process_id,
-                                                   render_view_id,
-                                                   stream_id,
-                                                   is_playing_and_audible);
+    bool is_playing, float power_dbfs, bool clipped) {
+  audio_stream_indicator_->UpdateWebContentsStatus(
+      render_process_id, render_view_id, stream_id,
+      is_playing, power_dbfs, clipped);
+}
+
+void MediaCaptureDevicesDispatcher::OnCreatingAudioStream(
+    int render_process_id,
+    int render_view_id) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+  BrowserThread::PostTask(
+      BrowserThread::UI, FROM_HERE,
+      base::Bind(
+          &MediaCaptureDevicesDispatcher::OnCreatingAudioStreamOnUIThread,
+          base::Unretained(this), render_process_id, render_view_id));
 }
 
 void MediaCaptureDevicesDispatcher::UpdateAudioDevicesOnUIThread(
@@ -526,3 +548,11 @@
                                     device,
                                     state));
 }
+
+void MediaCaptureDevicesDispatcher::OnCreatingAudioStreamOnUIThread(
+    int render_process_id,
+    int render_view_id) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  FOR_EACH_OBSERVER(Observer, observers_,
+                    OnCreatingAudioStream(render_process_id, render_view_id));
+}
diff --git a/chrome/browser/media/media_capture_devices_dispatcher.h b/chrome/browser/media/media_capture_devices_dispatcher.h
index 6054a30..e9dde12 100644
--- a/chrome/browser/media/media_capture_devices_dispatcher.h
+++ b/chrome/browser/media/media_capture_devices_dispatcher.h
@@ -54,6 +54,10 @@
         const content::MediaStreamDevice& device,
         const content::MediaRequestState state) {}
 
+    // Handle an information update that a new stream is being created.
+    virtual void OnCreatingAudioStream(int render_process_id,
+                                       int render_view_id) {}
+
     virtual ~Observer() {}
   };
 
@@ -121,7 +125,11 @@
       int render_process_id,
       int render_view_id,
       int stream_id,
-      bool is_playing_and_audible) OVERRIDE;
+      bool is_playing,
+      float power_dBFS,
+      bool clipped) OVERRIDE;
+  virtual void OnCreatingAudioStream(int render_process_id,
+                                     int render_view_id) OVERRIDE;
 
   scoped_refptr<MediaStreamCaptureIndicator> GetMediaStreamCaptureIndicator();
 
@@ -153,7 +161,8 @@
   void ProcessScreenCaptureAccessRequest(
       content::WebContents* web_contents,
       const content::MediaStreamRequest& request,
-      const content::MediaResponseCallback& callback);
+      const content::MediaResponseCallback& callback,
+      bool from_component_extension);
   void ProcessMediaAccessRequestFromExtension(
       content::WebContents* web_contents,
       const content::MediaStreamRequest& request,
@@ -177,6 +186,8 @@
       int page_request_id,
       const content::MediaStreamDevice& device,
       content::MediaRequestState state);
+  void OnCreatingAudioStreamOnUIThread(int render_process_id,
+                                       int render_view_id);
 
   // A list of cached audio capture devices.
   content::MediaStreamDevices audio_devices_;
diff --git a/chrome/browser/media/media_stream_capture_indicator.cc b/chrome/browser/media/media_stream_capture_indicator.cc
index 42598a6..456fc9d 100644
--- a/chrome/browser/media/media_stream_capture_indicator.cc
+++ b/chrome/browser/media/media_stream_capture_indicator.cc
@@ -55,7 +55,7 @@
     return NULL;
 
   return extension_service->extensions()->GetExtensionOrAppByURL(
-      ExtensionURLInfo(web_contents->GetURL()));
+      web_contents->GetURL());
 }
 
 // Gets the security originator of the tab. It returns a string with no '/'
@@ -379,7 +379,8 @@
   if (!status_tray)
     return;
 
-  status_icon_ = status_tray->CreateStatusIcon();
+  status_icon_ =
+      status_tray->CreateStatusIcon(StatusTray::MEDIA_STREAM_CAPTURE_ICON);
 
   EnsureStatusTrayIconResources();
 }
diff --git a/chrome/browser/media/media_stream_infobar_delegate.cc b/chrome/browser/media/media_stream_infobar_delegate.cc
index 3fc8661..5e2aa87 100644
--- a/chrome/browser/media/media_stream_infobar_delegate.cc
+++ b/chrome/browser/media/media_stream_infobar_delegate.cc
@@ -65,6 +65,7 @@
   DCHECK(controller_.get());
   DCHECK(controller_->has_audio() || controller_->has_video());
 }
+
 void MediaStreamInfoBarDelegate::InfoBarDismissed() {
   // Deny the request if the infobar was closed with the 'x' button, since
   // we don't want WebRTC to be waiting for an answer that will never come.
diff --git a/chrome/browser/media/media_stream_infobar_delegate.h b/chrome/browser/media/media_stream_infobar_delegate.h
index 02992e7..b2aaeeb 100644
--- a/chrome/browser/media/media_stream_infobar_delegate.h
+++ b/chrome/browser/media/media_stream_infobar_delegate.h
@@ -22,9 +22,9 @@
   virtual ~MediaStreamInfoBarDelegate();
 
   // Handles a permission request (in |request|) for |web_contents|.  If this
-  // involves prompting the user, creates a media stream delegate, then checks
-  // for an existing infobar for |web_contents| and replaces it if found, or
-  // just adds the new infobar otherwise.  Returns whether an infobar was
+  // involves prompting the user, creates a media stream infobar delegate, then
+  // checks for an existing infobar for |web_contents| and replaces it if found,
+  // or just adds the new infobar otherwise.  Returns whether an infobar was
   // created.
   static bool Create(content::WebContents* web_contents,
                      const content::MediaStreamRequest& request,
diff --git a/chrome/browser/media/webrtc_log_upload_list.cc b/chrome/browser/media/webrtc_log_upload_list.cc
index fdaaad0..9f9922e 100644
--- a/chrome/browser/media/webrtc_log_upload_list.cc
+++ b/chrome/browser/media/webrtc_log_upload_list.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/media/webrtc_log_upload_list.h"
 
 #include "base/files/file_path.h"
+#include "base/message_loop/message_loop_proxy.h"
 #include "base/path_service.h"
 #include "chrome/common/chrome_paths.h"
 
@@ -23,6 +24,8 @@
 
 WebRtcLogUploadList::WebRtcLogUploadList(Delegate* delegate,
                                          const base::FilePath& upload_log_path)
-    : UploadList(delegate, upload_log_path) {}
+    : base::UploadList(delegate,
+                       upload_log_path,
+                       base::MessageLoopProxy::current()) {}
 
 WebRtcLogUploadList::~WebRtcLogUploadList() {}
diff --git a/chrome/browser/media/webrtc_log_upload_list.h b/chrome/browser/media/webrtc_log_upload_list.h
index b829d8e..366a41d 100644
--- a/chrome/browser/media/webrtc_log_upload_list.h
+++ b/chrome/browser/media/webrtc_log_upload_list.h
@@ -5,10 +5,10 @@
 #ifndef CHROME_BROWSER_MEDIA_WEBRTC_LOG_UPLOAD_LIST_H_
 #define CHROME_BROWSER_MEDIA_WEBRTC_LOG_UPLOAD_LIST_H_
 
-#include "chrome/browser/upload_list.h"
+#include "base/upload_list.h"
 
 // Loads and parses a text file list of uploaded WebRTC logs.
-class WebRtcLogUploadList : public UploadList {
+class WebRtcLogUploadList : public base::UploadList {
  public:
   // Creates the WebRTC log upload list with the given callback delegate.
   static WebRtcLogUploadList* Create(Delegate* delegate);
diff --git a/chrome/browser/media_galleries/fileapi/itunes_data_provider.h b/chrome/browser/media_galleries/fileapi/itunes_data_provider.h
index 5d8cb4f..c53f552 100644
--- a/chrome/browser/media_galleries/fileapi/itunes_data_provider.h
+++ b/chrome/browser/media_galleries/fileapi/itunes_data_provider.h
@@ -17,6 +17,8 @@
 
 namespace itunes {
 
+class TestITunesDataProvider;
+
 // This class is the holder for iTunes parsed data. Given a path to the iTunes
 // library XML file it will read it in, parse the data, and provide convenient
 // methods to access it.  When the file changes, it will update the data.
@@ -30,7 +32,7 @@
   typedef base::Callback<void(bool)> ReadyCallback;
 
   explicit ITunesDataProvider(const base::FilePath& library_path);
-  ~ITunesDataProvider();
+  virtual ~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.
@@ -61,6 +63,8 @@
   Album GetAlbum(const ArtistName& artist, const AlbumName& album) const;
 
  private:
+  friend class TestITunesDataProvider;
+
   typedef std::map<AlbumName, Album> Artist;
   typedef std::map<ArtistName, Artist> Library;
 
@@ -79,8 +83,8 @@
   // 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 |library_path_| has changed. Virtual for testing.
+  virtual 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,
diff --git a/chrome/browser/media_galleries/fileapi/itunes_data_provider_browsertest.cc b/chrome/browser/media_galleries/fileapi/itunes_data_provider_browsertest.cc
new file mode 100644
index 0000000..2f1742a
--- /dev/null
+++ b/chrome/browser/media_galleries/fileapi/itunes_data_provider_browsertest.cc
@@ -0,0 +1,412 @@
+// Copyright 2013 The Chromium Authors. 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 <vector>
+
+#include "base/bind.h"
+#include "base/file_util.h"
+#include "base/files/file_path.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/format_macros.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/strings/stringprintf.h"
+#include "chrome/browser/media_galleries/fileapi/itunes_data_provider.h"
+#include "chrome/browser/media_galleries/fileapi/media_file_system_backend.h"
+#include "chrome/browser/media_galleries/imported_media_gallery_registry.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "content/public/browser/browser_thread.h"
+#include "url/gurl.h"
+
+using chrome::MediaFileSystemBackend;
+
+namespace itunes {
+
+namespace {
+
+struct LibraryEntry {
+  LibraryEntry(const std::string& artist, const std::string& album,
+               const base::FilePath& location)
+      : artist(artist),
+        album(album),
+        location(location) {
+  }
+  std::string artist;
+  std::string album;
+  base::FilePath location;
+};
+
+}  // namespace
+
+class TestITunesDataProvider : public ITunesDataProvider {
+ public:
+  TestITunesDataProvider(const base::FilePath& xml_library_path,
+                         const base::Closure& callback)
+      : ITunesDataProvider(xml_library_path),
+        callback_(callback) {
+  }
+  virtual ~TestITunesDataProvider() {}
+
+ private:
+  virtual void OnLibraryChanged(const base::FilePath& path,
+                                bool error) OVERRIDE {
+    ITunesDataProvider::OnLibraryChanged(path, error);
+    callback_.Run();
+  }
+
+  base::Closure callback_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestITunesDataProvider);
+};
+
+class ITunesDataProviderTest : public InProcessBrowserTest {
+ public:
+  ITunesDataProviderTest() {}
+  virtual ~ITunesDataProviderTest() {}
+
+ protected:
+  virtual void SetUp() OVERRIDE {
+    ASSERT_TRUE(library_dir_.CreateUniqueTempDir());
+    WriteLibraryInternal(SetUpLibrary());
+    // The ImportedMediaGalleryRegistry is created on which ever thread calls
+    // GetInstance() first.  It shouldn't matter what thread creates, however
+    // in practice it is always created on the UI thread, so this calls
+    // GetInstance here to mirror those real conditions.
+    chrome::ImportedMediaGalleryRegistry::GetInstance();
+    InProcessBrowserTest::SetUp();
+  }
+
+  void RunTest() {
+    DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+    base::RunLoop loop;
+    quit_closure_ = loop.QuitClosure();
+    MediaFileSystemBackend::MediaTaskRunner()->PostTask(
+        FROM_HERE,
+        base::Bind(&ITunesDataProviderTest::StartTestOnMediaTaskRunner,
+                   base::Unretained(this)));
+    loop.Run();
+  }
+
+  void WriteLibrary(const std::vector<LibraryEntry>& entries,
+                    const base::Closure& callback) {
+    SetLibraryChangeCallback(callback);
+    WriteLibraryInternal(entries);
+  }
+
+  void SetLibraryChangeCallback(const base::Closure& callback) {
+    EXPECT_TRUE(library_changed_callback_.is_null());
+    library_changed_callback_ = callback;
+  }
+
+  ITunesDataProvider* data_provider() const {
+    return chrome::ImportedMediaGalleryRegistry::ITunesDataProvider();
+  }
+
+  const base::FilePath& library_dir() const {
+    return library_dir_.path();
+  }
+
+  base::FilePath XmlFile() const {
+    return library_dir_.path().AppendASCII("library.xml");
+  }
+
+  void ExpectTrackLocation(const std::string& artist, const std::string& album,
+                           const std::string& track_name) {
+    base::FilePath track =
+        library_dir().AppendASCII(track_name).NormalizePathSeparators();
+    EXPECT_EQ(track.value(),
+              data_provider()->GetTrackLocation(
+                  artist, album, track_name).NormalizePathSeparators().value());
+  }
+
+  void ExpectNoTrack(const std::string& artist, const std::string& album,
+                     const std::string& track_name) {
+    EXPECT_TRUE(data_provider()->GetTrackLocation(
+          artist, album, track_name).empty()) << track_name;
+  }
+
+
+  // Get the initial set of library entries, called by SetUp.  If no entries
+  // are returned the xml file is not created.
+  virtual std::vector<LibraryEntry> SetUpLibrary() {
+    return std::vector<LibraryEntry>();
+  }
+
+  // Start the test. The data provider is refreshed before calling StartTest
+  // and the result of the refresh is passed in.
+  virtual void StartTest(bool parse_success) = 0;
+
+  void TestDone() {
+    DCHECK(MediaFileSystemBackend::CurrentlyOnMediaTaskRunnerThread());
+    chrome::ImportedMediaGalleryRegistry* imported_registry =
+        chrome::ImportedMediaGalleryRegistry::GetInstance();
+    imported_registry->itunes_data_provider_.reset();
+    content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
+                                     quit_closure_);
+  }
+
+ private:
+  void StartTestOnMediaTaskRunner() {
+    DCHECK(MediaFileSystemBackend::CurrentlyOnMediaTaskRunnerThread());
+    chrome::ImportedMediaGalleryRegistry* imported_registry =
+        chrome::ImportedMediaGalleryRegistry::GetInstance();
+    imported_registry->itunes_data_provider_.reset(
+        new TestITunesDataProvider(
+            XmlFile(),
+            base::Bind(&ITunesDataProviderTest::OnLibraryChanged,
+                       base::Unretained(this))));
+    data_provider()->RefreshData(base::Bind(&ITunesDataProviderTest::StartTest,
+                                            base::Unretained(this)));
+  };
+
+  void OnLibraryChanged() {
+    DCHECK(MediaFileSystemBackend::CurrentlyOnMediaTaskRunnerThread());
+    if (!library_changed_callback_.is_null()) {
+      library_changed_callback_.Run();
+      library_changed_callback_.Reset();
+    }
+  }
+
+  void WriteLibraryInternal(const std::vector<LibraryEntry>& entries) {
+    if (!entries.size())
+      return;
+    std::string xml = "<plist><dict><key>Tracks</key><dict>\n";
+    for (size_t i = 0; i < entries.size(); ++i) {
+      GURL location("file://localhost/" + entries[i].location.AsUTF8Unsafe());
+      std::string entry_string = base::StringPrintf(
+          "<key>%" PRIuS "</key><dict>\n"
+          "  <key>Track ID</key><integer>%" PRIuS "</integer>\n"
+          "  <key>Location</key><string>%s</string>\n"
+          "  <key>Artist</key><string>%s</string>\n"
+          "  <key>Album</key><string>%s</string>\n"
+          "</dict>\n",
+          i + 1, i + 1, location.spec().c_str(), entries[i].artist.c_str(),
+          entries[i].album.c_str());
+      xml += entry_string;
+    }
+    xml += "</dict></dict></plist>\n";
+    ASSERT_EQ(static_cast<int>(xml.size()),
+              file_util::WriteFile(XmlFile(), xml.c_str(), xml.size()));
+  }
+
+  base::ScopedTempDir library_dir_;
+
+  base::Closure library_changed_callback_;
+
+  base::Closure quit_closure_;
+
+  DISALLOW_COPY_AND_ASSIGN(ITunesDataProviderTest);
+};
+
+class ITunesDataProviderBasicTest : public ITunesDataProviderTest {
+ public:
+  ITunesDataProviderBasicTest() {}
+  virtual ~ITunesDataProviderBasicTest() {}
+
+  virtual std::vector<LibraryEntry> SetUpLibrary() OVERRIDE {
+    base::FilePath track = library_dir().AppendASCII("Track.mp3");
+    std::vector<LibraryEntry> entries;
+    entries.push_back(LibraryEntry("Artist", "Album", track));
+    return entries;
+  }
+
+  virtual void StartTest(bool parse_success) OVERRIDE {
+    EXPECT_TRUE(parse_success);
+
+    // KnownArtist
+    EXPECT_TRUE(data_provider()->KnownArtist("Artist"));
+    EXPECT_FALSE(data_provider()->KnownArtist("Artist2"));
+
+    // KnownAlbum
+    EXPECT_TRUE(data_provider()->KnownAlbum("Artist", "Album"));
+    EXPECT_FALSE(data_provider()->KnownAlbum("Artist", "Album2"));
+    EXPECT_FALSE(data_provider()->KnownAlbum("Artist2", "Album"));
+
+    // GetTrackLocation
+    ExpectTrackLocation("Artist", "Album", "Track.mp3");
+    ExpectNoTrack("Artist", "Album", "Track2.mp3");
+    ExpectNoTrack("Artist", "Album2", "Track.mp3");
+    ExpectNoTrack("Artist2", "Album", "Track.mp3");
+
+    // GetArtistNames
+    std::set<ITunesDataProvider::ArtistName> artists =
+      data_provider()->GetArtistNames();
+    ASSERT_EQ(1U, artists.size());
+    EXPECT_EQ("Artist", *artists.begin());
+
+    // GetAlbumNames
+    std::set<ITunesDataProvider::AlbumName> albums =
+        data_provider()->GetAlbumNames("Artist");
+    ASSERT_EQ(1U, albums.size());
+    EXPECT_EQ("Album", *albums.begin());
+
+    albums = data_provider()->GetAlbumNames("Artist2");
+    EXPECT_EQ(0U, albums.size());
+
+    // GetAlbum
+    base::FilePath track =
+        library_dir().AppendASCII("Track.mp3").NormalizePathSeparators();
+    ITunesDataProvider::Album album =
+        data_provider()->GetAlbum("Artist", "Album");
+    ASSERT_EQ(1U, album.size());
+    EXPECT_EQ(track.BaseName().AsUTF8Unsafe(), album.begin()->first);
+    EXPECT_EQ(track.value(),
+              album.begin()->second.NormalizePathSeparators().value());
+
+    album = data_provider()->GetAlbum("Artist", "Album2");
+    EXPECT_EQ(0U, album.size());
+
+    album = data_provider()->GetAlbum("Artist2", "Album");
+    EXPECT_EQ(0U, album.size());
+
+    TestDone();
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ITunesDataProviderBasicTest);
+};
+
+class ITunesDataProviderRefreshTest : public ITunesDataProviderTest {
+ public:
+  ITunesDataProviderRefreshTest() {}
+  virtual ~ITunesDataProviderRefreshTest() {}
+
+  virtual std::vector<LibraryEntry> SetUpLibrary() OVERRIDE {
+    base::FilePath track = library_dir().AppendASCII("Track.mp3");
+    std::vector<LibraryEntry> entries;
+    entries.push_back(LibraryEntry("Artist", "Album", track));
+    return entries;
+  }
+
+  virtual void StartTest(bool parse_success) OVERRIDE {
+    EXPECT_TRUE(parse_success);
+
+    // Initial contents.
+    ExpectTrackLocation("Artist", "Album", "Track.mp3");
+    ExpectNoTrack("Artist2", "Album2", "Track2.mp3");
+
+    // New file.
+    base::FilePath track2 = library_dir().AppendASCII("Track2.mp3");
+    std::vector<LibraryEntry> entries;
+    entries.push_back(LibraryEntry("Artist2", "Album2", track2));
+    WriteLibrary(entries,
+                 base::Bind(&ITunesDataProviderRefreshTest::CheckAfterWrite,
+                            base::Unretained(this)));
+  }
+
+  void CheckAfterWrite() {
+    // Content the same.
+    ExpectTrackLocation("Artist", "Album", "Track.mp3");
+    ExpectNoTrack("Artist2", "Album2", "Track2.mp3");
+
+    data_provider()->RefreshData(
+        base::Bind(&ITunesDataProviderRefreshTest::CheckRefresh,
+                   base::Unretained(this)));
+  }
+
+  void CheckRefresh(bool is_valid) {
+    EXPECT_TRUE(is_valid);
+
+    ExpectTrackLocation("Artist2", "Album2", "Track2.mp3");
+    ExpectNoTrack("Artist", "Album", "Track.mp3");
+    TestDone();
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ITunesDataProviderRefreshTest);
+};
+
+class ITunesDataProviderInvalidTest : public ITunesDataProviderTest {
+ public:
+  ITunesDataProviderInvalidTest() {}
+  virtual ~ITunesDataProviderInvalidTest() {}
+
+  virtual std::vector<LibraryEntry> SetUpLibrary() OVERRIDE {
+    base::FilePath track = library_dir().AppendASCII("Track.mp3");
+    std::vector<LibraryEntry> entries;
+    entries.push_back(LibraryEntry("Artist", "Album", track));
+    return entries;
+  }
+
+  virtual void StartTest(bool parse_success) OVERRIDE {
+    EXPECT_TRUE(parse_success);
+
+    SetLibraryChangeCallback(
+        base::Bind(&ITunesDataProvider::RefreshData,
+                   base::Unretained(data_provider()),
+                   base::Bind(&ITunesDataProviderInvalidTest::CheckInvalid,
+                              base::Unretained(this))));
+    ASSERT_EQ(1L, file_util::WriteFile(XmlFile(), " ", 1));
+  }
+
+  void CheckInvalid(bool is_valid) {
+    EXPECT_FALSE(is_valid);
+    TestDone();
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ITunesDataProviderInvalidTest);
+};
+
+class ITunesDataProviderUniqueNameTest : public ITunesDataProviderTest {
+ public:
+  ITunesDataProviderUniqueNameTest() {}
+  virtual ~ITunesDataProviderUniqueNameTest() {}
+
+  virtual std::vector<LibraryEntry> SetUpLibrary() OVERRIDE {
+    base::FilePath track = library_dir().AppendASCII("Track.mp3");
+    std::vector<LibraryEntry> entries;
+    // Dupe album names should get uniquified with the track id, which in the
+    // test framework is the vector index.
+    entries.push_back(LibraryEntry("Artist", "Album", track));
+    entries.push_back(LibraryEntry("Artist", "Album", track));
+    entries.push_back(LibraryEntry("Artist", "Album2", track));
+    return entries;
+  }
+
+  virtual void StartTest(bool parse_success) OVERRIDE {
+    EXPECT_TRUE(parse_success);
+
+    base::FilePath track =
+        library_dir().AppendASCII("Track.mp3").NormalizePathSeparators();
+    EXPECT_EQ(track.value(),
+              data_provider()->GetTrackLocation(
+                  "Artist", "Album",
+                  "Track (1).mp3").NormalizePathSeparators().value());
+    EXPECT_EQ(track.value(),
+              data_provider()->GetTrackLocation(
+                  "Artist", "Album",
+                  "Track (2).mp3").NormalizePathSeparators().value());
+    EXPECT_EQ(track.value(),
+              data_provider()->GetTrackLocation(
+                  "Artist", "Album2",
+                  "Track.mp3").NormalizePathSeparators().value());
+
+    TestDone();
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ITunesDataProviderUniqueNameTest);
+};
+
+IN_PROC_BROWSER_TEST_F(ITunesDataProviderBasicTest, BasicTest) {
+  RunTest();
+}
+
+IN_PROC_BROWSER_TEST_F(ITunesDataProviderRefreshTest, RefreshTest) {
+  RunTest();
+}
+
+IN_PROC_BROWSER_TEST_F(ITunesDataProviderInvalidTest, InvalidTest) {
+  RunTest();
+}
+
+IN_PROC_BROWSER_TEST_F(ITunesDataProviderUniqueNameTest, UniqueNameTest) {
+  RunTest();
+}
+
+}  // namespace itunes
diff --git a/chrome/browser/media_galleries/fileapi/itunes_finder_win_browsertest.cc b/chrome/browser/media_galleries/fileapi/itunes_finder_win_browsertest.cc
index 6182ede..9aeb450 100644
--- a/chrome/browser/media_galleries/fileapi/itunes_finder_win_browsertest.cc
+++ b/chrome/browser/media_galleries/fileapi/itunes_finder_win_browsertest.cc
@@ -9,7 +9,7 @@
 #include "base/files/scoped_temp_dir.h"
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "base/path_service.h"
 #include "base/run_loop.h"
 #include "base/strings/stringprintf.h"
@@ -38,6 +38,8 @@
  public:
   ITunesFinderWinTest() : test_finder_callback_called_(false) {}
 
+  virtual ~ITunesFinderWinTest() {}
+
   virtual void SetUp() OVERRIDE {
     ASSERT_TRUE(app_data_dir_.CreateUniqueTempDir());
     ASSERT_TRUE(music_dir_.CreateUniqueTempDir());
diff --git a/chrome/browser/media_galleries/imported_media_gallery_registry.h b/chrome/browser/media_galleries/imported_media_gallery_registry.h
index f90e7c1..b9bff98 100644
--- a/chrome/browser/media_galleries/imported_media_gallery_registry.h
+++ b/chrome/browser/media_galleries/imported_media_gallery_registry.h
@@ -15,6 +15,7 @@
 
 namespace itunes {
 class ITunesDataProvider;
+class ITunesDataProviderTest;
 }
 
 namespace picasa {
@@ -49,6 +50,7 @@
 
  private:
   friend struct base::DefaultLazyInstanceTraits<ImportedMediaGalleryRegistry>;
+  friend class itunes::ITunesDataProviderTest;
 
   ImportedMediaGalleryRegistry();
   virtual ~ImportedMediaGalleryRegistry();
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 7e71717..3543759 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
@@ -10,7 +10,7 @@
 #include "base/mac/cocoa_protocols.h"
 #include "base/mac/foundation_util.h"
 #include "base/mac/scoped_nsobject.h"
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/synchronization/waitable_event.h"
@@ -184,7 +184,9 @@
         content::BrowserThread::IO));
     ASSERT_TRUE(io_thread_->Start());
 
-    manager_.SetNotifications(monitor_.receiver());
+    chrome::test::TestStorageMonitor* monitor =
+        chrome::test::TestStorageMonitor::CreateAndInstall();
+    manager_.SetNotifications(monitor->receiver());
 
     camera_ = [MockMTPICCameraDevice alloc];
     id<ICDeviceBrowserDelegate> delegate = manager_.device_browser();
@@ -304,7 +306,6 @@
   scoped_ptr<content::TestBrowserThread> file_thread_;
   scoped_ptr<content::TestBrowserThread> io_thread_;
   base::ScopedTempDir temp_dir_;
-  chrome::test::TestStorageMonitor monitor_;
   chrome::ImageCaptureDeviceManager manager_;
   MockMTPICCameraDevice* camera_;
 
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 59a411b..cab5d3c 100644
--- a/chrome/browser/media_galleries/media_file_system_registry_unittest.cc
+++ b/chrome/browser/media_galleries/media_file_system_registry_unittest.cc
@@ -14,7 +14,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/scoped_vector.h"
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "base/path_service.h"
 #include "base/run_loop.h"
 #include "base/stl_util.h"
diff --git a/chrome/browser/media_galleries/media_galleries_preferences_unittest.cc b/chrome/browser/media_galleries/media_galleries_preferences_unittest.cc
index e4c208c..aa3b47d 100644
--- a/chrome/browser/media_galleries/media_galleries_preferences_unittest.cc
+++ b/chrome/browser/media_galleries/media_galleries_preferences_unittest.cc
@@ -9,7 +9,7 @@
 #include "base/command_line.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
 #include "chrome/browser/extensions/extension_system.h"
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
index 8f7d042..93fd983 100644
--- 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
@@ -6,7 +6,7 @@
 
 #include "base/command_line.h"
 #include "base/files/file_path.h"
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/stl_util.h"
 #include "chrome/browser/browser_process.h"
@@ -18,9 +18,11 @@
 #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.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_browser_process.h"
 #include "chrome/test/base/testing_profile.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/web_contents.h"
@@ -60,8 +62,8 @@
                         bool removable,
                         bool media_device);
 
-  // Note: need to make this weak ptr once ownership moves to g_browser_process
-  scoped_ptr<test::TestStorageMonitorWin> monitor_;
+  // Pointer to the storage monitor. Owned by TestingBrowserProcess.
+  test::TestStorageMonitorWin* monitor_;
   scoped_refptr<extensions::Extension> extension_;
 
   EnsureMediaDirectoriesExists media_directories_;
@@ -69,13 +71,21 @@
 
 void MTPDeviceDelegateImplWinTest::SetUp() {
   ChromeRenderViewHostTestHarness::SetUp();
+
+  test::TestStorageMonitor::RemoveSingleton();
   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));
+  scoped_ptr<test::TestStorageMonitorWin> monitor(
+      new test::TestStorageMonitorWin(
+          mount_watcher, portable_device_watcher));
+  TestingBrowserProcess* browser_process = TestingBrowserProcess::GetGlobal();
+  DCHECK(browser_process);
+  monitor_ = monitor.get();
+  browser_process->SetStorageMonitor(monitor.Pass());
+
   base::RunLoop runloop;
   monitor_->EnsureInitialized(runloop.QuitClosure());
   runloop.Run();
@@ -93,7 +103,9 @@
 }
 
 void MTPDeviceDelegateImplWinTest::TearDown() {
-  monitor_.reset();
+  // Windows storage monitor must be destroyed on the same thread
+  // as construction.
+  test::TestStorageMonitor::RemoveSingleton();
 
   ChromeRenderViewHostTestHarness::TearDown();
 }
diff --git a/chrome/browser/memory_details.cc b/chrome/browser/memory_details.cc
index ef07356..1dad6f9 100644
--- a/chrome/browser/memory_details.cc
+++ b/chrome/browser/memory_details.cc
@@ -497,6 +497,12 @@
 
 #if defined(OS_CHROMEOS)
 void MemoryDetails::UpdateSwapHistograms() {
+  UMA_HISTOGRAM_BOOLEAN("Memory.Swap.HaveSwapped", swap_data_.num_writes > 0);
+  if (swap_data_.num_writes == 0)
+    return;
+
+  // Only record swap info when any swaps have happened, to give us more
+  // detail in the histograms.
   const ProcessData& browser = *ChromeBrowser();
   size_t aggregate_memory = 0;
   for (size_t index = 0; index < browser.processes.size(); index++) {
@@ -563,6 +569,25 @@
 
   int total_sample = static_cast<int>(aggregate_memory / 1000);
   UMA_HISTOGRAM_MEMORY_MB("Memory.Swap.Total", total_sample);
+
+  UMA_HISTOGRAM_CUSTOM_COUNTS("Memory.Swap.CompressedDataSize",
+                              swap_data_.compr_data_size / (1024 * 1024),
+                              1, 4096, 50);
+  UMA_HISTOGRAM_CUSTOM_COUNTS("Memory.Swap.OriginalDataSize",
+                              swap_data_.orig_data_size / (1024 * 1024),
+                              1, 4096, 50);
+  UMA_HISTOGRAM_CUSTOM_COUNTS("Memory.Swap.MemUsedTotal",
+                              swap_data_.mem_used_total / (1024 * 1024),
+                              1, 4096, 50);
+  UMA_HISTOGRAM_COUNTS("Memory.Swap.NumReads", swap_data_.num_reads);
+  UMA_HISTOGRAM_COUNTS("Memory.Swap.NumWrites", swap_data_.num_writes);
+
+  if (swap_data_.orig_data_size > 0 && swap_data_.compr_data_size > 0) {
+    UMA_HISTOGRAM_CUSTOM_COUNTS(
+        "Memory.Swap.CompressionRatio",
+        swap_data_.orig_data_size / swap_data_.compr_data_size,
+        1, 20, 20);
+  }
 }
 
 #endif
diff --git a/chrome/browser/memory_details.h b/chrome/browser/memory_details.h
index 24abeb9..be4d51f 100644
--- a/chrome/browser/memory_details.h
+++ b/chrome/browser/memory_details.h
@@ -87,6 +87,24 @@
 class ProcessInfoSnapshot;
 #endif
 
+#if defined(OS_CHROMEOS)
+struct SwapData {
+  SwapData()
+      : num_reads(0),
+        num_writes(0),
+        compr_data_size(0),
+        orig_data_size(0),
+        mem_used_total(0) {
+  }
+
+  uint64 num_reads;
+  uint64 num_writes;
+  uint64 compr_data_size;
+  uint64 orig_data_size;
+  uint64 mem_used_total;
+};
+#endif
+
 // MemoryDetails fetches memory details about current running browsers.
 // Because this data can only be fetched asynchronously, callers use
 // this class via a callback.
@@ -187,6 +205,10 @@
 
   UserMetricsMode user_metrics_mode_;
 
+#if defined(OS_CHROMEOS)
+  SwapData swap_data_;
+#endif
+
   DISALLOW_COPY_AND_ASSIGN(MemoryDetails);
 };
 
diff --git a/chrome/browser/memory_details_linux.cc b/chrome/browser/memory_details_linux.cc
index 6c2a55c..31bed8d 100644
--- a/chrome/browser/memory_details_linux.cc
+++ b/chrome/browser/memory_details_linux.cc
@@ -11,7 +11,9 @@
 #include <set>
 
 #include "base/bind.h"
+#include "base/file_util.h"
 #include "base/process_util.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_constants.h"
@@ -160,6 +162,40 @@
   return children;
 }
 
+#if defined(OS_CHROMEOS)
+static uint64 ReadFileToUint64(const base::FilePath file) {
+  std::string file_as_string;
+  if (!file_util::ReadFileToString(file, &file_as_string))
+    return 0;
+  uint64 file_as_uint64;
+  if (!base::StringToUint64(file_as_string, &file_as_uint64))
+    return 0;
+  return file_as_uint64;
+}
+
+static void GetSwapData(SwapData* swap_data) {
+  base::FilePath zram_path("/sys/block/zram0");
+  uint64 orig_data_size = ReadFileToUint64(zram_path.Append("orig_data_size"));
+  if (orig_data_size <= 4096) {
+    // A single page is compressed at startup, and has a high compression
+    // ratio. We ignore this as it doesn't indicate any real swapping.
+    swap_data->orig_data_size = 0;
+    swap_data->num_reads = 0;
+    swap_data->num_writes = 0;
+    swap_data->compr_data_size = 0;
+    swap_data->mem_used_total = 0;
+    return;
+  }
+  swap_data->orig_data_size = orig_data_size;
+  swap_data->num_reads = ReadFileToUint64(zram_path.Append("num_reads"));
+  swap_data->num_writes = ReadFileToUint64(zram_path.Append("num_writes"));
+  swap_data->compr_data_size =
+      ReadFileToUint64(zram_path.Append("compr_data_size"));
+  swap_data->mem_used_total =
+      ReadFileToUint64(zram_path.Append("mem_used_total"));
+}
+#endif
+
 void MemoryDetails::CollectProcessData(
     const std::vector<ProcessMemoryInformation>& child_info) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
@@ -230,6 +266,10 @@
     process_data_.push_back(browser);
   }
 
+#if defined(OS_CHROMEOS)
+  GetSwapData(&swap_data_);
+#endif
+
   // Finally return to the browser thread.
   BrowserThread::PostTask(
       BrowserThread::UI, FROM_HERE,
diff --git a/chrome/browser/metrics/metrics_log.cc b/chrome/browser/metrics/metrics_log.cc
index 76563f59..af2613f 100644
--- a/chrome/browser/metrics/metrics_log.cc
+++ b/chrome/browser/metrics/metrics_log.cc
@@ -10,6 +10,7 @@
 
 #include "base/basictypes.h"
 #include "base/bind.h"
+#include "base/cpu.h"
 #include "base/lazy_instance.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/perftimer.h"
@@ -43,13 +44,13 @@
 #include "components/nacl/common/nacl_process_type.h"
 #include "content/public/browser/gpu_data_manager.h"
 #include "content/public/common/content_client.h"
+#include "content/public/common/webplugininfo.h"
 #include "device/bluetooth/bluetooth_adapter.h"
 #include "device/bluetooth/bluetooth_adapter_factory.h"
 #include "device/bluetooth/bluetooth_device.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)
 #include "base/android/build_info.h"
@@ -192,7 +193,7 @@
 }
 
 // Fills |plugin| with the info contained in |plugin_info| and |plugin_prefs|.
-void SetPluginInfo(const webkit::WebPluginInfo& plugin_info,
+void SetPluginInfo(const content::WebPluginInfo& plugin_info,
                    const PluginPrefs* plugin_prefs,
                    SystemProfileProto::Plugin* plugin) {
   plugin->set_name(UTF16ToUTF8(plugin_info.name));
@@ -219,27 +220,17 @@
   for (std::vector<tracked_objects::TaskSnapshot>::const_iterator it =
            profiler_data.tasks.begin();
        it != profiler_data.tasks.end(); ++it) {
-    std::string ignored;
-    uint64 birth_thread_name_hash;
-    uint64 exec_thread_name_hash;
-    uint64 source_file_name_hash;
-    uint64 source_function_name_hash;
-    MetricsLogBase::CreateHashes(it->birth.thread_name,
-                                 &ignored, &birth_thread_name_hash);
-    MetricsLogBase::CreateHashes(it->death_thread_name,
-                                 &ignored, &exec_thread_name_hash);
-    MetricsLogBase::CreateHashes(it->birth.location.file_name,
-                                 &ignored, &source_file_name_hash);
-    MetricsLogBase::CreateHashes(it->birth.location.function_name,
-                                 &ignored, &source_function_name_hash);
-
     const tracked_objects::DeathDataSnapshot& death_data = it->death_data;
     ProfilerEventProto::TrackedObject* tracked_object =
         performance_profile->add_tracked_object();
-    tracked_object->set_birth_thread_name_hash(birth_thread_name_hash);
-    tracked_object->set_exec_thread_name_hash(exec_thread_name_hash);
-    tracked_object->set_source_file_name_hash(source_file_name_hash);
-    tracked_object->set_source_function_name_hash(source_function_name_hash);
+    tracked_object->set_birth_thread_name_hash(
+        MetricsLogBase::Hash(it->birth.thread_name));
+    tracked_object->set_exec_thread_name_hash(
+        MetricsLogBase::Hash(it->death_thread_name));
+    tracked_object->set_source_file_name_hash(
+        MetricsLogBase::Hash(it->birth.location.file_name));
+    tracked_object->set_source_function_name_hash(
+        MetricsLogBase::Hash(it->birth.location.function_name));
     tracked_object->set_source_line_number(it->birth.location.line_number);
     tracked_object->set_exec_count(death_data.count);
     tracked_object->set_exec_time_total(death_data.run_duration_sum);
@@ -414,7 +405,7 @@
 }
 
 void MetricsLog::RecordIncrementalStabilityElements(
-    const std::vector<webkit::WebPluginInfo>& plugin_list) {
+    const std::vector<content::WebPluginInfo>& plugin_list) {
   DCHECK(!locked());
 
   PrefService* pref = GetPrefService();
@@ -449,7 +440,7 @@
 }
 
 void MetricsLog::WriteStabilityElement(
-    const std::vector<webkit::WebPluginInfo>& plugin_list,
+    const std::vector<content::WebPluginInfo>& plugin_list,
     PrefService* pref) {
   DCHECK(!locked());
 
@@ -492,7 +483,7 @@
 }
 
 void MetricsLog::WritePluginStabilityElements(
-    const std::vector<webkit::WebPluginInfo>& plugin_list,
+    const std::vector<content::WebPluginInfo>& plugin_list,
     PrefService* pref) {
   // Now log plugin stability info.
   const ListValue* plugin_stats_list = pref->GetList(
@@ -518,11 +509,11 @@
     // fine.
     // TODO(isherman): Verify that this does not show up as a hotspot in
     // profiler runs.
-    const webkit::WebPluginInfo* plugin_info = NULL;
+    const content::WebPluginInfo* plugin_info = NULL;
     std::string plugin_name;
     plugin_dict->GetString(prefs::kStabilityPluginName, &plugin_name);
     const string16 plugin_name_utf16 = UTF8ToUTF16(plugin_name);
-    for (std::vector<webkit::WebPluginInfo>::const_iterator iter =
+    for (std::vector<content::WebPluginInfo>::const_iterator iter =
              plugin_list.begin();
          iter != plugin_list.end(); ++iter) {
       if (iter->name == plugin_name_utf16) {
@@ -646,13 +637,13 @@
 }
 
 void MetricsLog::WritePluginList(
-    const std::vector<webkit::WebPluginInfo>& plugin_list) {
+    const std::vector<content::WebPluginInfo>& plugin_list) {
   DCHECK(!locked());
 
 #if defined(ENABLE_PLUGINS)
   PluginPrefs* plugin_prefs = GetPluginPrefs();
   SystemProfileProto* system_profile = uma_proto()->mutable_system_profile();
-  for (std::vector<webkit::WebPluginInfo>::const_iterator iter =
+  for (std::vector<content::WebPluginInfo>::const_iterator iter =
            plugin_list.begin();
        iter != plugin_list.end(); ++iter) {
     SystemProfileProto::Plugin* plugin = system_profile->add_plugin();
@@ -662,7 +653,7 @@
 }
 
 void MetricsLog::RecordEnvironment(
-         const std::vector<webkit::WebPluginInfo>& plugin_list,
+         const std::vector<content::WebPluginInfo>& plugin_list,
          const GoogleUpdateMetrics& google_update_metrics) {
   DCHECK(!locked());
 
@@ -673,7 +664,7 @@
 }
 
 void MetricsLog::RecordEnvironmentProto(
-    const std::vector<webkit::WebPluginInfo>& plugin_list,
+    const std::vector<content::WebPluginInfo>& plugin_list,
     const GoogleUpdateMetrics& google_update_metrics) {
   SystemProfileProto* system_profile = uma_proto()->mutable_system_profile();
 
@@ -732,6 +723,11 @@
       base::android::BuildInfo::GetInstance()->android_build_fp());
 #endif
 
+  base::CPU cpu_info;
+  SystemProfileProto::Hardware::CPU* cpu = hardware->mutable_cpu();
+  cpu->set_vendor_name(cpu_info.vendor_name());
+  cpu->set_signature(cpu_info.signature());
+
   const gpu::GPUInfo& gpu_info =
       GpuDataManager::GetInstance()->GetGPUInfo();
   SystemProfileProto::Hardware::Graphics* gpu = hardware->mutable_gpu();
diff --git a/chrome/browser/metrics/metrics_log.h b/chrome/browser/metrics/metrics_log.h
index abc0847..fe06b61 100644
--- a/chrome/browser/metrics/metrics_log.h
+++ b/chrome/browser/metrics/metrics_log.h
@@ -30,6 +30,10 @@
 class DictionaryValue;
 }
 
+namespace content {
+struct WebPluginInfo;
+}
+
 namespace device {
 class BluetoothAdapter;
 }
@@ -42,10 +46,6 @@
 struct ActiveGroupId;
 }
 
-namespace webkit {
-struct WebPluginInfo;
-}
-
 // This is a small helper struct to pass Google Update metrics in a single
 // reference argument to MetricsLog::RecordEnvironment().
 struct GoogleUpdateMetrics {
@@ -94,7 +94,7 @@
   // that are to be recorded. Each value in profile_metrics should be a
   // dictionary giving the metrics for the profile.
   void RecordEnvironment(
-      const std::vector<webkit::WebPluginInfo>& plugin_list,
+      const std::vector<content::WebPluginInfo>& plugin_list,
       const GoogleUpdateMetrics& google_update_metrics);
 
   // Records the current operating environment.  Takes the list of installed
@@ -104,7 +104,7 @@
   // environment with *each* protobuf upload, but only with the initial XML
   // upload.
   void RecordEnvironmentProto(
-      const std::vector<webkit::WebPluginInfo>& plugin_list,
+      const std::vector<content::WebPluginInfo>& plugin_list,
       const GoogleUpdateMetrics& google_update_metrics);
 
   // Records the input text, available choices, and selected entry when the
@@ -124,7 +124,7 @@
   // installed plugins as a parameter because that can't be obtained
   // synchronously from the UI thread.
   void RecordIncrementalStabilityElements(
-      const std::vector<webkit::WebPluginInfo>& plugin_list);
+      const std::vector<content::WebPluginInfo>& plugin_list);
 
  protected:
   // Exposed for the sake of mocking in test code.
@@ -152,12 +152,12 @@
   // Writes application stability metrics (as part of the profile log).
   // NOTE: Has the side-effect of clearing those counts.
   void WriteStabilityElement(
-      const std::vector<webkit::WebPluginInfo>& plugin_list,
+      const std::vector<content::WebPluginInfo>& plugin_list,
       PrefService* pref);
 
   // Within stability group, write plugin crash stats.
   void WritePluginStabilityElements(
-      const std::vector<webkit::WebPluginInfo>& plugin_list,
+      const std::vector<content::WebPluginInfo>& plugin_list,
       PrefService* pref);
 
   // Within the stability group, write required attributes.
@@ -170,7 +170,7 @@
   void WriteRealtimeStabilityAttributes(PrefService* pref);
 
   // Writes the list of installed plugins.
-  void WritePluginList(const std::vector<webkit::WebPluginInfo>& plugin_list);
+  void WritePluginList(const std::vector<content::WebPluginInfo>& plugin_list);
 
   // Writes info about the Google Update install that is managing this client.
   // This is a no-op if called on a non-Windows platform.
diff --git a/chrome/browser/metrics/metrics_log_unittest.cc b/chrome/browser/metrics/metrics_log_unittest.cc
index 3f3506f..f102a86 100644
--- a/chrome/browser/metrics/metrics_log_unittest.cc
+++ b/chrome/browser/metrics/metrics_log_unittest.cc
@@ -5,7 +5,7 @@
 #include <string>
 
 #include "base/basictypes.h"
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "base/port.h"
 #include "base/prefs/pref_service.h"
 #include "base/prefs/testing_pref_service.h"
@@ -25,11 +25,11 @@
 #include "chrome/installer/util/google_update_settings.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/common/process_type.h"
+#include "content/public/common/webplugininfo.h"
 #include "content/public/test/test_utils.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)
 #include "chromeos/dbus/mock_dbus_thread_manager_without_gmock.h"
@@ -128,7 +128,7 @@
   void TestRecordEnvironment(bool proto_only) {
     TestMetricsLog log(kClientId, kSessionId);
 
-    std::vector<webkit::WebPluginInfo> plugins;
+    std::vector<content::WebPluginInfo> plugins;
     GoogleUpdateMetrics google_update_metrics;
     if (proto_only)
       log.RecordEnvironmentProto(plugins, google_update_metrics);
@@ -160,6 +160,10 @@
     EXPECT_EQ(kScreenScaleFactor, hardware.primary_screen_scale_factor());
     EXPECT_EQ(kScreenCount, hardware.screen_count());
 
+    EXPECT_TRUE(hardware.has_cpu());
+    EXPECT_TRUE(hardware.cpu().has_vendor_name());
+    EXPECT_TRUE(hardware.cpu().has_signature());
+
     // TODO(isherman): Verify other data written into the protobuf as a result
     // of this call.
   }
diff --git a/chrome/browser/metrics/metrics_service.cc b/chrome/browser/metrics/metrics_service.cc
index af6e5e2..d48eb7b 100644
--- a/chrome/browser/metrics/metrics_service.cc
+++ b/chrome/browser/metrics/metrics_service.cc
@@ -208,9 +208,9 @@
 #include "content/public/browser/user_metrics.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/process_type.h"
+#include "content/public/common/webplugininfo.h"
 #include "net/base/load_flags.h"
 #include "net/url_request/url_fetcher.h"
-#include "webkit/plugins/webplugininfo.h"
 
 // TODO(port): port browser_distribution.h.
 #if !defined(OS_POSIX)
@@ -909,13 +909,13 @@
       base::Bind(&MetricsService::OnInitTaskGotPluginInfo,
           self_ptr_factory_.GetWeakPtr()));
 #else
-  std::vector<webkit::WebPluginInfo> plugin_list_empty;
+  std::vector<content::WebPluginInfo> plugin_list_empty;
   OnInitTaskGotPluginInfo(plugin_list_empty);
 #endif  // defined(ENABLE_PLUGINS)
 }
 
 void MetricsService::OnInitTaskGotPluginInfo(
-    const std::vector<webkit::WebPluginInfo>& plugins) {
+    const std::vector<content::WebPluginInfo>& plugins) {
   DCHECK_EQ(INIT_TASK_SCHEDULED, state_);
   plugins_ = plugins;
 
@@ -1595,7 +1595,7 @@
 #endif  // OS_CHROMEOS
 
 void MetricsService::LogPluginLoadingError(const base::FilePath& plugin_path) {
-  webkit::WebPluginInfo plugin;
+  content::WebPluginInfo plugin;
   bool success =
       content::PluginService::GetInstance()->GetPluginInfoByPath(plugin_path,
                                                                  &plugin);
diff --git a/chrome/browser/metrics/metrics_service.h b/chrome/browser/metrics/metrics_service.h
index d9e274b..b84172a 100644
--- a/chrome/browser/metrics/metrics_service.h
+++ b/chrome/browser/metrics/metrics_service.h
@@ -46,6 +46,7 @@
 namespace content {
 class RenderProcessHost;
 class WebContents;
+struct WebPluginInfo;
 }
 
 namespace extensions {
@@ -65,10 +66,6 @@
 struct ProcessDataSnapshot;
 }
 
-namespace webkit {
-struct WebPluginInfo;
-}
-
 class MetricsService
     : public chrome_browser_metrics::TrackingSynchronizerObserver,
       public content::BrowserChildProcessObserver,
@@ -236,7 +233,7 @@
   // Callback from PluginService::GetPlugins() that continues the init task by
   // launching a task to gather Google Update statistics.
   void OnInitTaskGotPluginInfo(
-      const std::vector<webkit::WebPluginInfo>& plugins);
+      const std::vector<content::WebPluginInfo>& plugins);
 
   // Task launched by OnInitTaskGotPluginInfo() that continues the init task by
   // loading Google Update statistics.  Called on a blocking pool thread.
@@ -418,7 +415,7 @@
   std::string hardware_class_;
 
   // The list of plugins which was retrieved on the file thread.
-  std::vector<webkit::WebPluginInfo> plugins_;
+  std::vector<content::WebPluginInfo> plugins_;
 
   // Google Update statistics, which were retrieved on a blocking pool thread.
   GoogleUpdateMetrics google_update_metrics_;
diff --git a/chrome/browser/metrics/metrics_service_unittest.cc b/chrome/browser/metrics/metrics_service_unittest.cc
index 51d4e34..3e13221 100644
--- a/chrome/browser/metrics/metrics_service_unittest.cc
+++ b/chrome/browser/metrics/metrics_service_unittest.cc
@@ -6,7 +6,7 @@
 #include <string>
 
 #include "base/command_line.h"
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "chrome/browser/metrics/metrics_service.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
diff --git a/chrome/browser/metrics/thread_watcher.cc b/chrome/browser/metrics/thread_watcher.cc
index 39dc136..c8ee4cf 100644
--- a/chrome/browser/metrics/thread_watcher.cc
+++ b/chrome/browser/metrics/thread_watcher.cc
@@ -63,10 +63,6 @@
   NullPointerCrash(__LINE__);
 }
 
-NOINLINE void ThreadUnresponsive_WEBKIT() {
-  NullPointerCrash(__LINE__);
-}
-
 NOINLINE void ThreadUnresponsive_FILE() {
   NullPointerCrash(__LINE__);
 }
@@ -98,8 +94,6 @@
       return ThreadUnresponsive_UI();
     case BrowserThread::DB:
       return ThreadUnresponsive_DB();
-    case BrowserThread::WEBKIT_DEPRECATED:
-      return ThreadUnresponsive_WEBKIT();
     case BrowserThread::FILE:
       return ThreadUnresponsive_FILE();
     case BrowserThread::FILE_USER_BLOCKING:
diff --git a/chrome/browser/metrics/thread_watcher.h b/chrome/browser/metrics/thread_watcher.h
index 487d6de..c1706fc 100644
--- a/chrome/browser/metrics/thread_watcher.h
+++ b/chrome/browser/metrics/thread_watcher.h
@@ -51,7 +51,7 @@
 #include "base/gtest_prod_util.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "base/metrics/histogram.h"
 #include "base/synchronization/lock.h"
 #include "base/threading/platform_thread.h"
diff --git a/chrome/browser/metrics/thread_watcher_unittest.cc b/chrome/browser/metrics/thread_watcher_unittest.cc
index 6670722..f8cc88e 100644
--- a/chrome/browser/metrics/thread_watcher_unittest.cc
+++ b/chrome/browser/metrics/thread_watcher_unittest.cc
@@ -8,7 +8,7 @@
 #include "base/bind.h"
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "base/message_loop/message_loop_proxy.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
@@ -238,24 +238,23 @@
   static const TimeDelta kUnresponsiveTime;
   static const BrowserThread::ID io_thread_id;
   static const std::string io_thread_name;
-  static const BrowserThread::ID webkit_thread_id;
-  static const std::string webkit_thread_name;
+  static const BrowserThread::ID db_thread_id;
+  static const std::string db_thread_name;
   static const std::string crash_on_hang_seconds;
   static const std::string crash_on_hang_thread_names;
   static const std::string thread_names_and_live_threshold;
   static const std::string crash_on_hang_thread_data;
   CustomThreadWatcher* io_watcher_;
-  CustomThreadWatcher* webkit_watcher_;
+  CustomThreadWatcher* db_watcher_;
   ThreadWatcherList* thread_watcher_list_;
 
   ThreadWatcherTest()
       : setup_complete_(&lock_),
         initialized_(false) {
-    webkit_thread_.reset(new content::TestBrowserThread(
-        BrowserThread::WEBKIT_DEPRECATED));
+    db_thread_.reset(new content::TestBrowserThread(BrowserThread::DB));
     io_thread_.reset(new content::TestBrowserThread(BrowserThread::IO));
     watchdog_thread_.reset(new WatchDogThread());
-    webkit_thread_->Start();
+    db_thread_->Start();
     io_thread_->Start();
     watchdog_thread_->Start();
 
@@ -277,10 +276,10 @@
                                           kSleepTime, kUnresponsiveTime);
     EXPECT_EQ(io_watcher_, thread_watcher_list_->Find(io_thread_id));
 
-    // Create thread watcher object for the WEBKIT thread.
-    webkit_watcher_ = new CustomThreadWatcher(
-        webkit_thread_id, webkit_thread_name, kSleepTime, kUnresponsiveTime);
-    EXPECT_EQ(webkit_watcher_, thread_watcher_list_->Find(webkit_thread_id));
+    // Create thread watcher object for the DB thread.
+    db_watcher_ = new CustomThreadWatcher(
+        db_thread_id, db_thread_name, kSleepTime, kUnresponsiveTime);
+    EXPECT_EQ(db_watcher_, thread_watcher_list_->Find(db_thread_id));
 
     {
       base::AutoLock lock(lock_);
@@ -302,9 +301,9 @@
   virtual ~ThreadWatcherTest() {
     ThreadWatcherList::DeleteAll();
     io_watcher_ = NULL;
-    webkit_watcher_ = NULL;
+    db_watcher_ = NULL;
     io_thread_.reset();
-    webkit_thread_.reset();
+    db_thread_.reset();
     watchdog_thread_.reset();
     thread_watcher_list_ = NULL;
   }
@@ -313,7 +312,7 @@
   base::Lock lock_;
   base::ConditionVariable setup_complete_;
   bool initialized_;
-  scoped_ptr<content::TestBrowserThread> webkit_thread_;
+  scoped_ptr<content::TestBrowserThread> db_thread_;
   scoped_ptr<content::TestBrowserThread> io_thread_;
   scoped_ptr<WatchDogThread> watchdog_thread_;
 };
@@ -325,9 +324,8 @@
     TimeDelta::FromMilliseconds(500);
 const BrowserThread::ID ThreadWatcherTest::io_thread_id = BrowserThread::IO;
 const std::string ThreadWatcherTest::io_thread_name = "IO";
-const BrowserThread::ID ThreadWatcherTest::webkit_thread_id =
-    BrowserThread::WEBKIT_DEPRECATED;
-const std::string ThreadWatcherTest::webkit_thread_name = "WEBKIT";
+const BrowserThread::ID ThreadWatcherTest::db_thread_id = BrowserThread::DB;
+const std::string ThreadWatcherTest::db_thread_name = "DB";
 const std::string ThreadWatcherTest::crash_on_hang_thread_names = "UI,IO";
 const std::string ThreadWatcherTest::thread_names_and_live_threshold =
     "UI:4,IO:4";
@@ -441,12 +439,12 @@
   EXPECT_EQ(kUnresponsiveTime, io_watcher_->unresponsive_time());
   EXPECT_FALSE(io_watcher_->active());
 
-  // Check ThreadWatcher object of watched WEBKIT thread has correct data.
-  EXPECT_EQ(webkit_thread_id, webkit_watcher_->thread_id());
-  EXPECT_EQ(webkit_thread_name, webkit_watcher_->thread_name());
-  EXPECT_EQ(kSleepTime, webkit_watcher_->sleep_time());
-  EXPECT_EQ(kUnresponsiveTime, webkit_watcher_->unresponsive_time());
-  EXPECT_FALSE(webkit_watcher_->active());
+  // Check ThreadWatcher object of watched DB thread has correct data.
+  EXPECT_EQ(db_thread_id, db_watcher_->thread_id());
+  EXPECT_EQ(db_thread_name, db_watcher_->thread_name());
+  EXPECT_EQ(kSleepTime, db_watcher_->sleep_time());
+  EXPECT_EQ(kUnresponsiveTime, db_watcher_->unresponsive_time());
+  EXPECT_FALSE(db_watcher_->active());
 }
 
 // Test ActivateThreadWatching and DeActivateThreadWatching of IO thread. This
@@ -525,11 +523,11 @@
 
 // Test watching of multiple threads with all threads not responding.
 TEST_F(ThreadWatcherTest, MultipleThreadsResponding) {
-  // Check for WEBKIT thread to perform ping/pong messaging.
+  // Check for DB thread to perform ping/pong messaging.
   WatchDogThread::PostTask(
       FROM_HERE,
       base::Bind(&ThreadWatcher::ActivateThreadWatching,
-                 base::Unretained(webkit_watcher_)));
+                 base::Unretained(db_watcher_)));
 
   // Check for IO thread to perform ping/pong messaging.
   WatchDogThread::PostTask(
@@ -537,14 +535,14 @@
       base::Bind(&ThreadWatcher::ActivateThreadWatching,
                  base::Unretained(io_watcher_)));
 
-  // Verify WEBKIT thread is responding with ping/pong messaging.
-  webkit_watcher_->WaitForCheckResponse(
+  // Verify DB thread is responding with ping/pong messaging.
+  db_watcher_->WaitForCheckResponse(
       kUnresponsiveTime + TimeDelta::FromMinutes(1), SUCCESSFUL);
-  EXPECT_GT(webkit_watcher_->ping_sent_, static_cast<uint64>(0));
-  EXPECT_GT(webkit_watcher_->pong_received_, static_cast<uint64>(0));
-  EXPECT_GE(webkit_watcher_->ping_sequence_number_, static_cast<uint64>(0));
-  EXPECT_GT(webkit_watcher_->success_response_, static_cast<uint64>(0));
-  EXPECT_EQ(webkit_watcher_->failed_response_, static_cast<uint64>(0));
+  EXPECT_GT(db_watcher_->ping_sent_, static_cast<uint64>(0));
+  EXPECT_GT(db_watcher_->pong_received_, static_cast<uint64>(0));
+  EXPECT_GE(db_watcher_->ping_sequence_number_, static_cast<uint64>(0));
+  EXPECT_GT(db_watcher_->success_response_, static_cast<uint64>(0));
+  EXPECT_EQ(db_watcher_->failed_response_, static_cast<uint64>(0));
 
   // Verify IO thread is responding with ping/pong messaging.
   io_watcher_->WaitForCheckResponse(
@@ -564,7 +562,7 @@
   WatchDogThread::PostTask(
       FROM_HERE,
       base::Bind(&ThreadWatcher::DeActivateThreadWatching,
-                 base::Unretained(webkit_watcher_)));
+                 base::Unretained(db_watcher_)));
 }
 
 // Test watching of multiple threads with one of the threads not responding.
@@ -580,11 +578,11 @@
                  base::Unretained(io_watcher_),
                  kUnresponsiveTime * 10));
 
-  // Activate watching of WEBKIT thread.
+  // Activate watching of DB thread.
   WatchDogThread::PostTask(
       FROM_HERE,
       base::Bind(&ThreadWatcher::ActivateThreadWatching,
-                 base::Unretained(webkit_watcher_)));
+                 base::Unretained(db_watcher_)));
 
   // Activate watching of IO thread.
   WatchDogThread::PostTask(
@@ -592,11 +590,11 @@
       base::Bind(&ThreadWatcher::ActivateThreadWatching,
                  base::Unretained(io_watcher_)));
 
-  // Verify WEBKIT thread is responding with ping/pong messaging.
-  webkit_watcher_->WaitForCheckResponse(
+  // Verify DB thread is responding with ping/pong messaging.
+  db_watcher_->WaitForCheckResponse(
       kUnresponsiveTime + TimeDelta::FromMinutes(1), SUCCESSFUL);
-  EXPECT_GT(webkit_watcher_->success_response_, static_cast<uint64>(0));
-  EXPECT_EQ(webkit_watcher_->failed_response_, static_cast<uint64>(0));
+  EXPECT_GT(db_watcher_->success_response_, static_cast<uint64>(0));
+  EXPECT_EQ(db_watcher_->failed_response_, static_cast<uint64>(0));
 
   // Verify IO thread is not responding for ping messages.
   io_watcher_->WaitForCheckResponse(
@@ -612,7 +610,7 @@
   WatchDogThread::PostTask(
       FROM_HERE,
       base::Bind(&ThreadWatcher::DeActivateThreadWatching,
-                 base::Unretained(webkit_watcher_)));
+                 base::Unretained(db_watcher_)));
 
   // Wait for the io_watcher_'s VeryLongMethod to finish.
   io_watcher_->WaitForWaitStateChange(kUnresponsiveTime * 10, ALL_DONE);
diff --git a/chrome/browser/metrics/variations/variations_request_scheduler_unittest.cc b/chrome/browser/metrics/variations/variations_request_scheduler_unittest.cc
index f69a0b8..493275b 100644
--- a/chrome/browser/metrics/variations/variations_request_scheduler_unittest.cc
+++ b/chrome/browser/metrics/variations/variations_request_scheduler_unittest.cc
@@ -5,7 +5,7 @@
 #include "chrome/browser/metrics/variations/variations_request_scheduler.h"
 
 #include "base/bind.h"
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace chrome_variations {
diff --git a/chrome/browser/nacl_host/nacl_broker_host_win.cc b/chrome/browser/nacl_host/nacl_broker_host_win.cc
index f0eca4d..bcb250b 100644
--- a/chrome/browser/nacl_host/nacl_broker_host_win.cc
+++ b/chrome/browser/nacl_host/nacl_broker_host_win.cc
@@ -10,8 +10,8 @@
 #include "ipc/ipc_switches.h"
 #include "chrome/browser/nacl_host/nacl_broker_service_win.h"
 #include "chrome/browser/nacl_host/nacl_browser.h"
-#include "chrome/common/nacl_cmd_line.h"
 #include "chrome/common/nacl_messages.h"
+#include "components/nacl/common/nacl_cmd_line.h"
 #include "components/nacl/common/nacl_process_type.h"
 #include "components/nacl/common/nacl_switches.h"
 #include "content/public/browser/browser_child_process_host.h"
diff --git a/chrome/browser/nacl_host/nacl_browser.cc b/chrome/browser/nacl_host/nacl_browser.cc
index ea9ea0f..8460124 100644
--- a/chrome/browser/nacl_host/nacl_browser.cc
+++ b/chrome/browser/nacl_host/nacl_browser.cc
@@ -6,7 +6,7 @@
 
 #include "base/command_line.h"
 #include "base/file_util.h"
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "base/metrics/histogram.h"
 #include "base/path_service.h"
 #include "base/pickle.h"
diff --git a/chrome/browser/nacl_host/nacl_file_host.cc b/chrome/browser/nacl_host/nacl_file_host.cc
index 18efee9..ca1feb9 100644
--- a/chrome/browser/nacl_host/nacl_file_host.cc
+++ b/chrome/browser/nacl_host/nacl_file_host.cc
@@ -145,38 +145,6 @@
   nacl_host_message_filter->Send(reply_msg);
 }
 
-IPC::PlatformFileForTransit GetTemporaryFile(
-    scoped_refptr<NaClHostMessageFilter> nacl_host_message_filter) {
-  DCHECK(BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
-
-  base::FilePath file_path;
-  if (!file_util::CreateTemporaryFile(&file_path))
-    return IPC::InvalidPlatformFileForTransit();
-
-  base::PlatformFileError error;
-  base::PlatformFile file_handle = base::CreatePlatformFile(
-      file_path,
-      base::PLATFORM_FILE_CREATE_ALWAYS | base::PLATFORM_FILE_READ |
-      base::PLATFORM_FILE_WRITE | base::PLATFORM_FILE_TEMPORARY |
-      base::PLATFORM_FILE_DELETE_ON_CLOSE,
-      NULL, &error);
-
-  if (error != base::PLATFORM_FILE_OK)
-    return IPC::InvalidPlatformFileForTransit();
-
-  // Do any DuplicateHandle magic that is necessary first.
-  return IPC::GetFileHandleForProcess(file_handle,
-                                      nacl_host_message_filter->PeerHandle(),
-                                      true);
-}
-
-void ReturnTemporaryFileOnIOThread(
-    nacl_file_host::TempFileCallback cb,
-    IPC::PlatformFileForTransit fd) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-  cb.Run(fd);
-}
-
 void DoRegisterOpenedNaClExecutableFile(
     scoped_refptr<NaClHostMessageFilter> nacl_host_message_filter,
     base::PlatformFile file,
@@ -209,8 +177,7 @@
     base::FilePath* file_path) {
   // Check that the URL is recognized by the extension system.
   const extensions::Extension* extension =
-      extension_info_map->extensions().GetExtensionOrAppByURL(
-          ExtensionURLInfo(file_url));
+      extension_info_map->extensions().GetExtensionOrAppByURL(file_url);
   if (!extension)
     return false;
 
@@ -334,19 +301,6 @@
   return true;
 }
 
-void CreateTemporaryFile(
-    scoped_refptr<NaClHostMessageFilter> nacl_host_message_filter,
-    TempFileCallback cb) {
-    if (!base::PostTaskAndReplyWithResult(
-            BrowserThread::GetBlockingPool(),
-            FROM_HERE,
-            base::Bind(&GetTemporaryFile, nacl_host_message_filter),
-            base::Bind(&ReturnTemporaryFileOnIOThread, cb))) {
-    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-    cb.Run(IPC::InvalidPlatformFileForTransit());
-  }
-}
-
 void OpenNaClExecutable(
     scoped_refptr<NaClHostMessageFilter> nacl_host_message_filter,
     scoped_refptr<ExtensionInfoMap> extension_info_map,
diff --git a/chrome/browser/nacl_host/nacl_file_host.h b/chrome/browser/nacl_host/nacl_file_host.h
index b27a87e..ee473cc 100644
--- a/chrome/browser/nacl_host/nacl_file_host.h
+++ b/chrome/browser/nacl_host/nacl_file_host.h
@@ -7,9 +7,8 @@
 
 #include <string>
 
-#include "base/callback.h"
+#include "base/callback_forward.h"
 #include "base/memory/ref_counted.h"
-#include "ipc/ipc_platform_file.h"
 
 class ExtensionInfoMap;
 class GURL;
@@ -26,7 +25,6 @@
 // Opens NaCl Files in the Browser process, on behalf of the NaCl plugin.
 
 namespace nacl_file_host {
-typedef base::Callback<void(IPC::PlatformFileForTransit)> TempFileCallback;
 
 // Open a Pnacl file (readonly) on behalf of the NaCl plugin.
 void GetReadonlyPnaclFd(
@@ -39,12 +37,6 @@
 bool PnaclCanOpenFile(const std::string& filename,
                       base::FilePath* file_to_open);
 
-// Creates a temporary file that will be deleted when the last handle
-// is closed, or earlier.
-void CreateTemporaryFile(
-    scoped_refptr<NaClHostMessageFilter> nacl_host_message_filter,
-    TempFileCallback cb);
-
 // Opens a NaCl executable file for reading and executing.
 void OpenNaClExecutable(
     scoped_refptr<NaClHostMessageFilter> nacl_host_message_filter,
diff --git a/chrome/browser/nacl_host/nacl_host_message_filter.cc b/chrome/browser/nacl_host/nacl_host_message_filter.cc
index 01cc5f8..ceecc2a 100644
--- a/chrome/browser/nacl_host/nacl_host_message_filter.cc
+++ b/chrome/browser/nacl_host/nacl_host_message_filter.cc
@@ -8,6 +8,7 @@
 #include "chrome/browser/nacl_host/nacl_browser.h"
 #include "chrome/browser/nacl_host/nacl_file_host.h"
 #include "chrome/browser/nacl_host/nacl_process_host.h"
+#include "chrome/browser/nacl_host/pnacl_host.h"
 #include "chrome/common/nacl_host_messages.h"
 #include "extensions/common/constants.h"
 #include "net/url_request/url_request_context.h"
@@ -17,7 +18,7 @@
     ExtensionInfoMap* extension_info_map, const std::string& manifest) {
   GURL manifest_url(manifest);
   const extensions::Extension* extension = extension_info_map->extensions()
-      .GetExtensionOrAppByURL(ExtensionURLInfo(manifest_url));
+      .GetExtensionOrAppByURL(manifest_url);
   if (extension != NULL &&
       manifest_url.SchemeIs(extensions::kExtensionScheme)) {
     std::string path = manifest_url.path();
@@ -44,6 +45,11 @@
 NaClHostMessageFilter::~NaClHostMessageFilter() {
 }
 
+void NaClHostMessageFilter::OnChannelClosing() {
+  PnaclHost::GetInstance()->RendererClosing(render_process_id_);
+  BrowserMessageFilter::OnChannelClosing();
+}
+
 bool NaClHostMessageFilter::OnMessageReceived(const IPC::Message& message,
                                               bool* message_was_ok) {
   bool handled = true;
@@ -95,6 +101,10 @@
   // This posts a task to another thread, but the renderer will
   // block until the reply is sent.
   nacl_file_host::GetReadonlyPnaclFd(this, filename, reply_msg);
+
+  // This is the first message we receive from the renderer once it knows we
+  // want to use PNaCl, so start the translation cache initialization here.
+  PnaclHost::GetInstance()->Init();
 }
 
 // Return the temporary file via a reply to the
@@ -113,8 +123,8 @@
 
 void NaClHostMessageFilter::OnNaClCreateTemporaryFile(
     IPC::Message* reply_msg) {
-  nacl_file_host::CreateTemporaryFile(
-      this,
+  PnaclHost::GetInstance()->CreateTemporaryFile(
+      PeerHandle(),
       base::Bind(&NaClHostMessageFilter::SyncReturnTemporaryFile,
                  this,
                  reply_msg));
@@ -122,28 +132,40 @@
 
 // For now, GetNexeFd cache requests always set is_hit to false and returns
 // a new temporary file via a NaClViewMsg_NexeTempFileReply message.
-// A future CL will implement the cache lookup logic.
+// A future CL will implement the cache lookup logic (and use the currently-
+// unused parameters)
 // See also https://code.google.com/p/nativeclient/issues/detail?id=3372
 void NaClHostMessageFilter::AsyncReturnTemporaryFile(
-    int render_view_id,
-    IPC::PlatformFileForTransit fd) {
-  Send(new NaClViewMsg_NexeTempFileReply(render_view_id, false, fd));
+    int pp_instance,
+    IPC::PlatformFileForTransit fd,
+    bool is_hit) {
+  Send(new NaClViewMsg_NexeTempFileReply(pp_instance, is_hit, fd));
 }
 
 void NaClHostMessageFilter::OnGetNexeFd(
     int render_view_id,
+    int pp_instance,
     const nacl::PnaclCacheInfo& cache_info) {
-  nacl_file_host::CreateTemporaryFile(
-      this,
+  if (!cache_info.pexe_url.is_valid()) {
+    LOG(ERROR) << "Bad URL received from GetNexeFd: " <<
+        cache_info.pexe_url.possibly_invalid_spec();
+    BadMessageReceived();
+    return;
+  }
+  PnaclHost::GetInstance()->GetNexeFd(
+      render_process_id_,
+      PeerHandle(),
+      render_view_id,
+      pp_instance,
+      cache_info,
       base::Bind(&NaClHostMessageFilter::AsyncReturnTemporaryFile,
                  this,
-                 render_view_id));
+                 pp_instance));
 }
 
-// For now, ignore translation finished messages. A future CL will implement
-// the logic of reading the nexe from the temp file and storing it in the cache.
-// See also https://code.google.com/p/nativeclient/issues/detail?id=3372
-void NaClHostMessageFilter::OnTranslationFinished(int render_view_id) {
+void NaClHostMessageFilter::OnTranslationFinished(int instance) {
+  PnaclHost::GetInstance()->TranslationFinished(
+      render_process_id_, instance);
 }
 
 void NaClHostMessageFilter::OnNaClErrorStatus(int render_view_id,
diff --git a/chrome/browser/nacl_host/nacl_host_message_filter.h b/chrome/browser/nacl_host/nacl_host_message_filter.h
index 8c99c55..66af82d 100644
--- a/chrome/browser/nacl_host/nacl_host_message_filter.h
+++ b/chrome/browser/nacl_host/nacl_host_message_filter.h
@@ -36,6 +36,7 @@
   // content::BrowserMessageFilter methods:
   virtual bool OnMessageReceived(const IPC::Message& message,
                                  bool* message_was_ok) OVERRIDE;
+  virtual void OnChannelClosing() OVERRIDE;
 
   int render_process_id() { return render_process_id_; }
   bool off_the_record() { return off_the_record_; }
@@ -53,8 +54,10 @@
   void OnGetReadonlyPnaclFd(const std::string& filename,
                             IPC::Message* reply_msg);
   void OnNaClCreateTemporaryFile(IPC::Message* reply_msg);
-  void OnGetNexeFd(int render_view_id, const nacl::PnaclCacheInfo& cache_info);
-  void OnTranslationFinished(int render_view_id);
+  void OnGetNexeFd(int render_view_id,
+                   int pp_instance,
+                   const nacl::PnaclCacheInfo& cache_info);
+  void OnTranslationFinished(int instance);
   void OnNaClErrorStatus(int render_view_id, int error_id);
   void OnOpenNaClExecutable(int render_view_id,
                             const GURL& file_url,
@@ -62,8 +65,9 @@
 
   void SyncReturnTemporaryFile(IPC::Message* reply_msg,
                                IPC::PlatformFileForTransit fd);
-  void AsyncReturnTemporaryFile(int render_view_id,
-                                IPC::PlatformFileForTransit fd);
+  void AsyncReturnTemporaryFile(int pp_instance,
+                                IPC::PlatformFileForTransit fd,
+                                bool is_hit);
 #endif
   int render_process_id_;
 
diff --git a/chrome/browser/nacl_host/nacl_infobar_delegate.cc b/chrome/browser/nacl_host/nacl_infobar_delegate.cc
index b9e08b8..fecad03 100644
--- a/chrome/browser/nacl_host/nacl_infobar_delegate.cc
+++ b/chrome/browser/nacl_host/nacl_infobar_delegate.cc
@@ -24,9 +24,10 @@
     return;
   InfoBarService* infobar_service =
       InfoBarService::FromWebContents(web_contents);
-  if (infobar_service)
+  if (infobar_service) {
     infobar_service->AddInfoBar(scoped_ptr<InfoBarDelegate>(
         new NaClInfoBarDelegate(infobar_service)));
+  }
 }
 
 NaClInfoBarDelegate::NaClInfoBarDelegate(InfoBarService* infobar_service)
diff --git a/chrome/browser/nacl_host/nacl_infobar_delegate.h b/chrome/browser/nacl_host/nacl_infobar_delegate.h
index c3da4d4..2b3b4e9 100644
--- a/chrome/browser/nacl_host/nacl_infobar_delegate.h
+++ b/chrome/browser/nacl_host/nacl_infobar_delegate.h
@@ -9,8 +9,8 @@
 
 class NaClInfoBarDelegate : public ConfirmInfoBarDelegate {
  public:
-  // Creates a NaCl delegate and adds it to the infobar service corresponding to
-  // the given render process and view IDs.
+  // Creates a NaCl infobar delegate and adds it to the infobar service
+  // corresponding to the given render process and view IDs.
   static void Create(int render_process_id, int render_view_id);
 
  private:
diff --git a/chrome/browser/nacl_host/nacl_process_host.cc b/chrome/browser/nacl_host/nacl_process_host.cc
index df54445..ee67c58 100644
--- a/chrome/browser/nacl_host/nacl_process_host.cc
+++ b/chrome/browser/nacl_host/nacl_process_host.cc
@@ -12,7 +12,7 @@
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/file_util.h"
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "base/metrics/histogram.h"
 #include "base/path_service.h"
 #include "base/process_util.h"
@@ -25,10 +25,10 @@
 #include "build/build_config.h"
 #include "chrome/browser/nacl_host/nacl_browser.h"
 #include "chrome/browser/nacl_host/nacl_host_message_filter.h"
-#include "chrome/common/nacl_cmd_line.h"
 #include "chrome/common/nacl_host_messages.h"
 #include "chrome/common/nacl_messages.h"
 #include "components/nacl/common/nacl_browser_delegate.h"
+#include "components/nacl/common/nacl_cmd_line.h"
 #include "components/nacl/common/nacl_process_type.h"
 #include "components/nacl/common/nacl_switches.h"
 #include "content/public/browser/browser_child_process_host.h"
@@ -289,8 +289,8 @@
   NaClBrowser* nacl_browser = NaClBrowser::GetInstance();
   nacl_browser->EnsureAllResourcesAvailable();
   if (!nacl_browser->IsOk()) {
-    LOG(ERROR) << "NaCl process launch failed: could not find all the "
-        "resources needed to launch the process";
+    SendErrorToRenderer("could not find all the resources needed"
+                        " to launch the process");
     delete this;
     return;
   }
@@ -307,7 +307,7 @@
   NaClHandle pair[2];
   // Create a connected socket
   if (NaClSocketPair(pair) == -1) {
-    LOG(ERROR) << "NaCl process launch failed: could not create a socket pair";
+    SendErrorToRenderer("NaClSocketPair() failed");
     delete this;
     return;
   }
@@ -393,7 +393,7 @@
 bool NaClProcessHost::LaunchSelLdr() {
   std::string channel_id = process_->GetHost()->CreateChannel();
   if (channel_id.empty()) {
-    LOG(ERROR) << "NaCl process launch failed: could not create channel";
+    SendErrorToRenderer("CreateChannel() failed");
     return false;
   }
 
@@ -428,6 +428,7 @@
   // On Windows 64-bit NaCl loader is called nacl64.exe instead of chrome.exe
   if (RunningOnWOW64()) {
     if (!NaClBrowser::GetInstance()->GetNaCl64ExePath(&exe_path)) {
+      SendErrorToRenderer("could not get path to nacl64.exe");
       return false;
     }
   }
@@ -450,8 +451,7 @@
   if (RunningOnWOW64()) {
     if (!NaClBrokerService::GetInstance()->LaunchLoader(
             weak_factory_.GetWeakPtr(), channel_id)) {
-      LOG(ERROR) << "NaCl process launch failed: broker service did not launch "
-          "process";
+      SendErrorToRenderer("broker service did not launch process");
       return false;
     }
   } else {
@@ -496,8 +496,7 @@
 void NaClProcessHost::OnResourcesReady() {
   NaClBrowser* nacl_browser = NaClBrowser::GetInstance();
   if (!nacl_browser->IsReady()) {
-    LOG(ERROR) << "NaCl process launch failed: could not acquire shared "
-        "resources needed by NaCl";
+    SendErrorToRenderer("could not acquire shared resources needed by NaCl");
     delete this;
   } else if (!SendStart()) {
     delete this;
@@ -514,7 +513,7 @@
   // BrokerDuplicateHandle().
   if (RunningOnWOW64()) {
     if (!content::BrokerAddTargetPeer(process_->GetData().handle)) {
-      LOG(ERROR) << "Failed to add NaCl process PID";
+      SendErrorToRenderer("BrokerAddTargetPeer() failed");
       return false;
     }
   }
@@ -532,7 +531,7 @@
                        0,  // Unused given DUPLICATE_SAME_ACCESS.
                        FALSE,
                        DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
-    LOG(ERROR) << "DuplicateHandle() failed";
+    SendErrorToRenderer("DuplicateHandle() failed");
     return false;
   }
   handle_for_renderer = reinterpret_cast<nacl::FileDescriptor>(
@@ -547,16 +546,35 @@
 #endif
 
   const ChildProcessData& data = process_->GetData();
-  NaClHostMsg_LaunchNaCl::WriteReplyParams(
-      reply_msg_, handle_for_renderer,
-      channel_handle, base::GetProcId(data.handle), data.id);
-  nacl_host_message_filter_->Send(reply_msg_);
-  nacl_host_message_filter_ = NULL;
-  reply_msg_ = NULL;
+  SendMessageToRenderer(
+      nacl::NaClLaunchResult(handle_for_renderer,
+                             channel_handle,
+                             base::GetProcId(data.handle),
+                             data.id),
+      std::string() /* error_message */);
   internal_->socket_for_renderer = NACL_INVALID_HANDLE;
   return true;
 }
 
+void NaClProcessHost::SendErrorToRenderer(const std::string& error_message) {
+  LOG(ERROR) << "NaCl process launch failed: " << error_message;
+  SendMessageToRenderer(nacl::NaClLaunchResult(), error_message);
+}
+
+void NaClProcessHost::SendMessageToRenderer(
+    const nacl::NaClLaunchResult& result,
+    const std::string& error_message) {
+  DCHECK(nacl_host_message_filter_);
+  DCHECK(reply_msg_);
+  if (nacl_host_message_filter_ != NULL && reply_msg_ != NULL) {
+    NaClHostMsg_LaunchNaCl::WriteReplyParams(
+        reply_msg_, result, error_message);
+    nacl_host_message_filter_->Send(reply_msg_);
+    nacl_host_message_filter_ = NULL;
+    reply_msg_ = NULL;
+  }
+}
+
 // TCP port we chose for NaCl debug stub. It can be any other number.
 static const int kDebugStubPort = 4014;
 
@@ -755,8 +773,7 @@
                    weak_factory_.GetWeakPtr()));
     return true;
   } else {
-    LOG(ERROR) << "NaCl process failed to launch: previously failed to acquire "
-        "shared resources";
+    SendErrorToRenderer("previously failed to acquire shared resources");
     return false;
   }
 }
diff --git a/chrome/browser/nacl_host/nacl_process_host.h b/chrome/browser/nacl_host/nacl_process_host.h
index d68693d..1250b3c 100644
--- a/chrome/browser/nacl_host/nacl_process_host.h
+++ b/chrome/browser/nacl_host/nacl_process_host.h
@@ -11,7 +11,7 @@
 #include "base/files/file_util_proxy.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "base/process.h"
 #include "chrome/common/nacl_types.h"
 #include "content/public/browser/browser_child_process_host_delegate.h"
@@ -123,6 +123,14 @@
   // to load. Returns true on success.
   bool ReplyToRenderer(const IPC::ChannelHandle& channel_handle);
 
+  // Sends the reply with error message to the renderer.
+  void SendErrorToRenderer(const std::string& error_message);
+
+  // Sends the reply message to the renderer. Either result or
+  // error message must be empty.
+  void SendMessageToRenderer(const nacl::NaClLaunchResult& result,
+                             const std::string& error_message);
+
   // Sends the message to the NaCl process to load the plugin. Returns true
   // on success.
   bool StartNaClExecution();
diff --git a/chrome/browser/nacl_host/pnacl_host.cc b/chrome/browser/nacl_host/pnacl_host.cc
new file mode 100644
index 0000000..f3b7de2
--- /dev/null
+++ b/chrome/browser/nacl_host/pnacl_host.cc
@@ -0,0 +1,208 @@
+// Copyright 2013 The Chromium Authors. 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/nacl_host/pnacl_host.h"
+
+#include "base/bind.h"
+#include "base/file_util.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/nacl_host/nacl_browser.h"
+#include "chrome/browser/nacl_host/pnacl_translation_cache.h"
+#include "content/public/browser/browser_thread.h"
+#include "net/base/net_errors.h"
+
+using content::BrowserThread;
+
+namespace {
+static const base::FilePath::CharType kTranslationCacheDirectoryName[] =
+    FILE_PATH_LITERAL("PnaclTranslationCache");
+}
+
+PnaclHost::PnaclHost()
+    : cache_state_(CacheUninitialized), weak_factory_(this) {}
+
+PnaclHost::~PnaclHost() {}
+
+PnaclHost* PnaclHost::GetInstance() { return Singleton<PnaclHost>::get(); }
+
+PnaclHost::PendingTranslation::PendingTranslation() {}
+PnaclHost::PendingTranslation::~PendingTranslation() {}
+
+/////////////////////////////////////// Initialization
+
+static base::FilePath GetCachePath() {
+  NaClBrowserDelegate* browser_delegate = NaClBrowser::GetDelegate();
+  // Determine where the translation cache resides in the file system.  It
+  // exists in Chrome's cache directory and is not tied to any specific
+  // profile. If we fail, return an empty path.
+  // Start by finding the user data directory.
+  base::FilePath user_data_dir;
+  if (!browser_delegate ||
+      !browser_delegate->GetUserDirectory(&user_data_dir)) {
+    return base::FilePath();
+  }
+  // The cache directory may or may not be the user data directory.
+  base::FilePath cache_file_path;
+  browser_delegate->GetCacheDirectory(&cache_file_path);
+
+  // Append the base file name to the cache directory.
+  return cache_file_path.Append(kTranslationCacheDirectoryName);
+}
+
+void PnaclHost::OnCacheInitialized(int error) {
+  // If the cache was cleared before the load completed, ignore.
+  if (cache_state_ == CacheReady)
+    return;
+  if (error != net::OK) {
+    LOG(ERROR) << "PNaCl translation cache initalization failure: " << error
+               << "\n";
+  } else {
+    cache_state_ = CacheReady;
+  }
+}
+
+void PnaclHost::Init() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  base::FilePath cache_path(GetCachePath());
+  if (cache_path.empty() || cache_state_ != CacheUninitialized)
+    return;
+  disk_cache_.reset(new pnacl::PnaclTranslationCache());
+  cache_state_ = CacheInitializing;
+  disk_cache_->InitCache(
+      cache_path,
+      true,
+      base::Bind(&PnaclHost::OnCacheInitialized, weak_factory_.GetWeakPtr()));
+}
+
+// Initialize using the in-memory backend, and manually set the temporary file
+// directory instead of using the system directory.
+void PnaclHost::InitForTest(base::FilePath temp_dir) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  disk_cache_.reset(new pnacl::PnaclTranslationCache());
+  cache_state_ = CacheInitializing;
+  temp_dir_ = temp_dir;
+  disk_cache_->InitCache(
+      temp_dir,
+      true,  // Use in-memory backend
+      base::Bind(&PnaclHost::OnCacheInitialized, weak_factory_.GetWeakPtr()));
+}
+
+///////////////////////////////////////// Temp files
+
+// Create a temporary file on the blocking pool
+IPC::PlatformFileForTransit PnaclHost::DoCreateTemporaryFile(
+    base::ProcessHandle process_handle,
+    base::FilePath temp_dir) {
+  DCHECK(BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
+
+  base::FilePath file_path;
+  bool rv = temp_dir.empty()
+                ? file_util::CreateTemporaryFileInDir(temp_dir, &file_path)
+                : file_util::CreateTemporaryFile(&file_path);
+  if (!rv)
+    return IPC::InvalidPlatformFileForTransit();
+
+  base::PlatformFileError error;
+  base::PlatformFile file_handle(base::CreatePlatformFile(
+      file_path,
+      base::PLATFORM_FILE_CREATE_ALWAYS | base::PLATFORM_FILE_READ |
+          base::PLATFORM_FILE_WRITE | base::PLATFORM_FILE_TEMPORARY |
+          base::PLATFORM_FILE_DELETE_ON_CLOSE,
+      NULL,
+      &error));
+
+  if (error != base::PLATFORM_FILE_OK)
+    return IPC::InvalidPlatformFileForTransit();
+
+  // Do any DuplicateHandle magic that is necessary first.
+  return IPC::GetFileHandleForProcess(file_handle, process_handle, true);
+}
+
+void PnaclHost::CreateTemporaryFile(base::ProcessHandle process_handle,
+                                    TempFileCallback cb) {
+  if (!base::PostTaskAndReplyWithResult(
+          BrowserThread::GetBlockingPool(),
+          FROM_HERE,
+          base::Bind(
+              &PnaclHost::DoCreateTemporaryFile, process_handle, temp_dir_),
+          cb)) {
+    DCHECK(thread_checker_.CalledOnValidThread());
+    cb.Run(IPC::InvalidPlatformFileForTransit());
+  }
+}
+
+///////////////////////////////////////// GetNexeFd implementation
+
+void PnaclHost::ReturnMiss(TranslationID id, IPC::PlatformFileForTransit fd) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  PendingTranslationMap::iterator entry(pending_translations_.find(id));
+  if (entry == pending_translations_.end()) {
+    LOG(ERROR) << "PnaclHost::ReturnMiss: Failed to find TranslationID "
+               << id.first << "," << id.second;
+    return;
+  }
+  NexeFdCallback cb(entry->second.callback);
+  if (fd == IPC::InvalidPlatformFileForTransit()) {
+    pending_translations_.erase(entry);
+  } else {
+    entry->second.nexe_fd = fd;
+  }
+  cb.Run(fd, false);
+}
+
+void PnaclHost::GetNexeFd(int render_process_id,
+                          base::ProcessHandle process_handle,
+                          int render_view_id,
+                          int pp_instance,
+                          const nacl::PnaclCacheInfo& cache_info,
+                          const NexeFdCallback& cb) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  if (cache_state_ != CacheReady)
+    return;
+  PendingTranslation pt;
+  pt.render_view_id = render_view_id;
+  pt.callback = cb;
+  pt.cache_info = cache_info;
+
+  pending_translations_[TranslationID(render_process_id, pp_instance)] = pt;
+
+  CreateTemporaryFile(
+      process_handle,
+      base::Bind(&PnaclHost::ReturnMiss,
+                 weak_factory_.GetWeakPtr(),
+                 TranslationID(render_process_id, pp_instance)));
+}
+
+/////////////////// Cleanup
+
+void PnaclHost::TranslationFinished(int render_process_id, int pp_instance) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  if (cache_state_ != CacheReady)
+    return;
+  PendingTranslationMap::iterator it(pending_translations_.find(
+      TranslationID(render_process_id, pp_instance)));
+  if (it == pending_translations_.end()) {
+    LOG(ERROR) << "TranslationFinished: TranslationID " << render_process_id
+               << "," << pp_instance << " not found.";
+  } else {
+    pending_translations_.erase(it);
+  }
+}
+
+void PnaclHost::RendererClosing(int render_process_id) {
+  if (cache_state_ != CacheReady)
+    return;
+  DCHECK(thread_checker_.CalledOnValidThread());
+  for (PendingTranslationMap::iterator it = pending_translations_.begin();
+       it != pending_translations_.end();) {
+    PendingTranslationMap::iterator to_erase(it++);
+    if (to_erase->first.first == render_process_id) {
+      // clean up the open files
+      pending_translations_.erase(to_erase);
+    }
+  }
+}
diff --git a/chrome/browser/nacl_host/pnacl_host.h b/chrome/browser/nacl_host/pnacl_host.h
new file mode 100644
index 0000000..b55c9a6
--- /dev/null
+++ b/chrome/browser/nacl_host/pnacl_host.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_NACL_HOST_PNACL_HOST_H_
+#define CHROME_BROWSER_NACL_HOST_PNACL_HOST_H_
+
+#include <map>
+
+#include "base/callback_forward.h"
+#include "base/memory/singleton.h"
+#include "base/memory/weak_ptr.h"
+#include "base/threading/thread_checker.h"
+#include "chrome/browser/nacl_host/nacl_file_host.h"
+#include "chrome/common/pnacl_types.h"
+#include "ipc/ipc_platform_file.h"
+
+namespace pnacl {
+class PnaclHostTest;
+class PnaclTranslationCache;
+}
+
+// Shared state (translation cache) and common utilities (temp file creation)
+// for all PNaCl translations. Unless otherwise specified, all methods should be
+// called on the IO thread.
+class PnaclHost {
+ public:
+  typedef base::Callback<void(IPC::PlatformFileForTransit)> TempFileCallback;
+  typedef base::Callback<void(IPC::PlatformFileForTransit, bool is_hit)>
+      NexeFdCallback;
+
+  static PnaclHost* GetInstance();
+
+  PnaclHost();
+  ~PnaclHost();
+  void Init();
+
+  // Creates a temporary file that will be deleted when the last handle
+  // is closed, or earlier. Returns a PlatformFileForTransit usable by the
+  // process identified by |process_handle|.
+  void CreateTemporaryFile(base::ProcessHandle process_handle,
+                           TempFileCallback cb);
+
+  // Create a temporary file, which will be deleted by the time the last
+  // handle is closed (or earlier on POSIX systems), to use for the nexe
+  // with the cache information given in |cache_info|. The specific instance
+  // is identified by the combination of |render_process_id| and |pp_instance|.
+  // Returns by calling |cb| with a PlatformFileForTransit usable by the process
+  // identified by |process_handle|. If the nexe is already present
+  // in the cache, |is_hit| is set to true and the contents of the nexe
+  // have been copied into the temporary file. Otherwise |is_hit| is set to
+  // false and the temporary file will be writeable.
+  // Currently the implementation is a stub, which always sets is_hit to false
+  // and calls the implementation of CreateTemporaryFile.
+  // If the cache request was a miss, the caller is expected to call
+  // TranslationFinished after it finishes translation to allow the nexe to be
+  // stored in the cache.
+  void GetNexeFd(int render_process_id,
+                 base::ProcessHandle process_handle,
+                 int render_view_id,
+                 int pp_instance,
+                 const nacl::PnaclCacheInfo& cache_info,
+                 const NexeFdCallback& cb);
+
+  // Called after the translation of a pexe instance identified by
+  // |render_process_id| and |pp_instance| finishes. Store the nexe translated
+  // for the instance in the cache.
+  void TranslationFinished(int render_process_id, int pp_instance);
+
+  // Called when the renderer identified by |render_process_id| is closing.
+  // Clean up any outstanding translations for that renderer.
+  void RendererClosing(int render_process_id);
+
+ private:
+  // PnaclHost is a singleton because there is only one translation cache, and
+  // so that the BrowsingDataRemover can clear it even if no translation has
+  // ever been started.
+  friend struct DefaultSingletonTraits<PnaclHost>;
+  friend class pnacl::PnaclHostTest;
+  enum CacheState {
+    CacheUninitialized,
+    CacheInitializing,
+    CacheReady
+  };
+  struct PendingTranslation {
+   public:
+    PendingTranslation();
+    ~PendingTranslation();
+    int render_view_id;
+    IPC::PlatformFileForTransit nexe_fd;
+    NexeFdCallback callback;
+    nacl::PnaclCacheInfo cache_info;
+  };
+
+  typedef std::pair<int, int> TranslationID;
+  typedef std::map<TranslationID, PendingTranslation> PendingTranslationMap;
+
+  void InitForTest(base::FilePath temp_dir);
+  void OnCacheInitialized(int error);
+  static IPC::PlatformFileForTransit DoCreateTemporaryFile(
+      base::ProcessHandle process_handle,
+      base::FilePath temp_dir_);
+  void ReturnMiss(TranslationID id, IPC::PlatformFileForTransit fd);
+
+  CacheState cache_state_;
+  base::FilePath temp_dir_;
+  scoped_ptr<pnacl::PnaclTranslationCache> disk_cache_;
+  PendingTranslationMap pending_translations_;
+  base::ThreadChecker thread_checker_;
+  base::WeakPtrFactory<PnaclHost> weak_factory_;
+  DISALLOW_COPY_AND_ASSIGN(PnaclHost);
+};
+
+#endif  // CHROME_BROWSER_NACL_HOST_PNACL_HOST_H_
diff --git a/chrome/browser/nacl_host/pnacl_host_unittest.cc b/chrome/browser/nacl_host/pnacl_host_unittest.cc
new file mode 100644
index 0000000..7796aa6
--- /dev/null
+++ b/chrome/browser/nacl_host/pnacl_host_unittest.cc
@@ -0,0 +1,103 @@
+// Copyright 2013 The Chromium Authors. 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/nacl_host/pnacl_host.h"
+
+#include "base/bind.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/run_loop.h"
+#include "base/threading/sequenced_worker_pool.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace pnacl {
+
+class PnaclHostTest : public testing::Test {
+ protected:
+  PnaclHostTest()
+      : temp_callback_count_(0),
+        thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP) {}
+  virtual void SetUp() {
+    host_ = new PnaclHost();
+    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+    host_->InitForTest(temp_dir_.path());
+    EXPECT_EQ(host_->cache_state_, PnaclHost::CacheReady);
+  }
+  virtual void TearDown() {
+    ExpectPendingTranslations(0);
+    delete host_;
+  }
+  // Utilities for inspecting internal state of the pnacl host
+  void ExpectPendingTranslations(size_t count) {
+    EXPECT_EQ(count, host_->pending_translations_.size());
+  }
+  void ExpectCallbackCount(int count) {
+    EXPECT_EQ(count, temp_callback_count_);
+  }
+
+ public:  // Required for derived classes to bind this method
+  void CallbackExpectMiss(IPC::PlatformFileForTransit fd, bool is_hit) {
+    temp_callback_count_++;
+    EXPECT_FALSE(is_hit);
+    EXPECT_FALSE(fd == IPC::InvalidPlatformFileForTransit());
+  }
+
+ protected:
+  PnaclHost* host_;
+  int temp_callback_count_;
+  content::TestBrowserThreadBundle thread_bundle_;
+  base::ScopedTempDir temp_dir_;
+};
+
+#define EXPECT_PENDING_TRANSLATIONS(n) \
+  do {                                 \
+    SCOPED_TRACE("");                  \
+    ExpectPendingTranslations(n);      \
+  } while (0)
+
+// We don't do actual caching yet, but just return a new temp file with a miss
+TEST_F(PnaclHostTest, BasicMiss) {
+  nacl::PnaclCacheInfo info;
+  host_->GetNexeFd(
+      0,
+      base::ProcessHandle(),
+      0,
+      0,
+      info,
+      base::Bind(&PnaclHostTest::CallbackExpectMiss, base::Unretained(this)));
+
+  EXPECT_PENDING_TRANSLATIONS(1);
+  content::BrowserThread::GetBlockingPool()->FlushForTesting();
+  base::RunLoop().RunUntilIdle();
+  EXPECT_PENDING_TRANSLATIONS(1);
+  ExpectCallbackCount(1);
+  host_->TranslationFinished(0, 0);
+  EXPECT_PENDING_TRANSLATIONS(0);
+  host_->RendererClosing(0);
+}
+
+TEST_F(PnaclHostTest, BadArguments) {
+  nacl::PnaclCacheInfo info;
+  host_->GetNexeFd(
+      0,
+      base::ProcessHandle(),
+      0,
+      0,
+      info,
+      base::Bind(&PnaclHostTest::CallbackExpectMiss, base::Unretained(this)));
+
+  EXPECT_PENDING_TRANSLATIONS(1);
+  host_->TranslationFinished(0, 1);  // nonexistent translation
+  EXPECT_PENDING_TRANSLATIONS(1);
+  host_->RendererClosing(1);  // nonexistent renderer
+  EXPECT_PENDING_TRANSLATIONS(1);
+  content::BrowserThread::GetBlockingPool()->FlushForTesting();
+  base::RunLoop().RunUntilIdle();
+  ExpectCallbackCount(1);
+  host_->RendererClosing(0);  // close without finishing
+  EXPECT_PENDING_TRANSLATIONS(0);
+}
+
+}  // namespace pnacl
diff --git a/chrome/browser/nacl_host/pnacl_translation_cache.cc b/chrome/browser/nacl_host/pnacl_translation_cache.cc
index 155258b..6492e36 100644
--- a/chrome/browser/nacl_host/pnacl_translation_cache.cc
+++ b/chrome/browser/nacl_host/pnacl_translation_cache.cc
@@ -16,16 +16,13 @@
 
 using content::BrowserThread;
 
-static const base::FilePath::CharType kDiskCacheDirectoryName[] =
-    FILE_PATH_LITERAL("PnaclTranslationCache");
-
 namespace {
 
 void CloseDiskCacheEntry(disk_cache::Entry* entry) { entry->Close(); }
 
 }  // namespace
 
-namespace pnacl_cache {
+namespace pnacl {
 // These are in pnacl_cache namespace instead of static so they can be used
 // by the unit test.
 const int kMaxDiskCacheSize = 1000 * 1024 * 1024;
@@ -367,7 +364,7 @@
   if (in_memory_) {
     rv = InitWithMemBackend(kMaxMemCacheSize, callback);
   } else {
-    rv = InitWithDiskBackend(cache_directory.Append(kDiskCacheDirectoryName),
+    rv = InitWithDiskBackend(cache_directory,
                              kMaxDiskCacheSize,
                              callback);
   }
@@ -381,4 +378,4 @@
   return disk_cache_->GetEntryCount();
 }
 
-}  // namespace pnacl_cache
+}  // namespace pnacl
diff --git a/chrome/browser/nacl_host/pnacl_translation_cache.h b/chrome/browser/nacl_host/pnacl_translation_cache.h
index 6af0ddc..96f03c0 100644
--- a/chrome/browser/nacl_host/pnacl_translation_cache.h
+++ b/chrome/browser/nacl_host/pnacl_translation_cache.h
@@ -20,7 +20,7 @@
 class Backend;
 }
 
-namespace pnacl_cache {
+namespace pnacl {
 typedef base::Callback<void(int)> CompletionCallback;
 class PnaclTranslationCacheEntry;
 extern const int kMaxMemCacheSize;
@@ -85,6 +85,6 @@
   DISALLOW_COPY_AND_ASSIGN(PnaclTranslationCache);
 };
 
-}  // namespace pnacl_cache
+}  // namespace pnacl
 
 #endif  // CHROME_BROWSER_NACL_HOST_PNACL_TRANSLATION_CACHE_H_
diff --git a/chrome/browser/nacl_host/pnacl_translation_cache_unittest.cc b/chrome/browser/nacl_host/pnacl_translation_cache_unittest.cc
index a22db45..b2e8061 100644
--- a/chrome/browser/nacl_host/pnacl_translation_cache_unittest.cc
+++ b/chrome/browser/nacl_host/pnacl_translation_cache_unittest.cc
@@ -6,7 +6,7 @@
 
 #include "base/files/file_path.h"
 #include "base/files/scoped_temp_dir.h"
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/test/test_browser_thread_bundle.h"
@@ -16,7 +16,7 @@
 using content::BrowserThread;
 using base::FilePath;
 
-namespace pnacl_cache {
+namespace pnacl {
 
 class PnaclTranslationCacheTest : public testing::Test {
  protected:
@@ -155,4 +155,4 @@
   EXPECT_EQ(net::ERR_FAILED, load_cb.GetResult(net::ERR_IO_PENDING));
 }
 
-}  // namespace pnacl_cache
+}  // namespace pnacl
diff --git a/chrome/browser/net/connection_tester.cc b/chrome/browser/net/connection_tester.cc
index 347761c..5127d55 100644
--- a/chrome/browser/net/connection_tester.cc
+++ b/chrome/browser/net/connection_tester.cc
@@ -113,7 +113,9 @@
     storage_.set_ssl_config_service(new net::SSLConfigServiceDefaults);
     storage_.set_http_auth_handler_factory(
         net::HttpAuthHandlerFactory::CreateDefault(host_resolver()));
-    storage_.set_http_server_properties(new net::HttpServerPropertiesImpl);
+    storage_.set_http_server_properties(
+        scoped_ptr<net::HttpServerProperties>(
+            new net::HttpServerPropertiesImpl()));
 
     net::HttpNetworkSession::Params session_params;
     session_params.host_resolver = host_resolver();
diff --git a/chrome/browser/net/connection_tester_unittest.cc b/chrome/browser/net/connection_tester_unittest.cc
index 5d87aa1..f5ecb59 100644
--- a/chrome/browser/net/connection_tester_unittest.cc
+++ b/chrome/browser/net/connection_tester_unittest.cc
@@ -138,7 +138,8 @@
     session_params.http_auth_handler_factory = &http_auth_handler_factory_;
     session_params.ssl_config_service = ssl_config_service_.get();
     session_params.proxy_service = proxy_service_.get();
-    session_params.http_server_properties = &http_server_properties_impl_;
+    session_params.http_server_properties =
+        http_server_properties_impl_.GetWeakPtr();
     scoped_refptr<net::HttpNetworkSession> network_session(
         new net::HttpNetworkSession(session_params));
     http_transaction_factory_.reset(
diff --git a/chrome/browser/net/dns_probe_browsertest.cc b/chrome/browser/net/dns_probe_browsertest.cc
index 5c3dfaf..3e11252 100644
--- a/chrome/browser/net/dns_probe_browsertest.cc
+++ b/chrome/browser/net/dns_probe_browsertest.cc
@@ -467,8 +467,7 @@
 // Double-check to make sure sync failures don't explode.
 IN_PROC_BROWSER_TEST_F(DnsProbeBrowserTest, SyncFailureWithBrokenLinkDoctor) {
   SetLinkDoctorBroken(true);
-  SetMockDnsClientRules(MockDnsClientRule::FAIL_SYNC,
-                        MockDnsClientRule::FAIL_SYNC);
+  SetMockDnsClientRules(MockDnsClientRule::FAIL, MockDnsClientRule::FAIL);
 
   NavigateToDnsError();
 
diff --git a/chrome/browser/net/dns_probe_runner.cc b/chrome/browser/net/dns_probe_runner.cc
index d2b3a5d..ce5aed5 100644
--- a/chrome/browser/net/dns_probe_runner.cc
+++ b/chrome/browser/net/dns_probe_runner.cc
@@ -24,6 +24,7 @@
 using net::DnsClient;
 using net::DnsResponse;
 using net::DnsTransaction;
+using net::DnsTransactionFactory;
 using net::IPAddressNumber;
 using net::IPEndPoint;
 using net::NetLog;
@@ -44,7 +45,7 @@
       break;
 
     // ERR_NAME_NOT_RESOLVED maps to NXDOMAIN, which means the server is working
-    // but gave us a wrong answer.
+    // but returned a wrong answer.
     case net::ERR_NAME_NOT_RESOLVED:
       return DnsProbeRunner::INCORRECT;
 
@@ -68,15 +69,12 @@
   TimeDelta ttl;
   DnsResponse::Result result = response->ParseToAddressList(&addr_list, &ttl);
 
-  if (result != DnsResponse::DNS_PARSE_OK) {
+  if (result != DnsResponse::DNS_PARSE_OK)
     return DnsProbeRunner::FAILING;
-  }
-
-  if (addr_list.empty()) {
+  else if (addr_list.empty())
     return DnsProbeRunner::INCORRECT;
-  }
-
-  return DnsProbeRunner::CORRECT;
+  else
+    return DnsProbeRunner::CORRECT;
 }
 
 }  // namespace
@@ -96,16 +94,27 @@
   DCHECK(!transaction_.get());
 
   callback_ = callback;
-  transaction_ = client_->GetTransactionFactory()->CreateTransaction(
+  DnsTransactionFactory* factory = client_->GetTransactionFactory();
+  if (!factory) {
+    // If the DnsTransactionFactory is NULL, then the DnsConfig is invalid, so
+    // the runner can't run a transaction.  Return UNKNOWN asynchronously.
+    result_ = UNKNOWN;
+    BrowserThread::PostTask(
+        BrowserThread::IO,
+        FROM_HERE,
+        base::Bind(&DnsProbeRunner::CallCallback,
+                   weak_factory_.GetWeakPtr()));
+    return;
+  }
+
+  transaction_ = factory->CreateTransaction(
       kKnownGoodHostname,
       net::dns_protocol::kTypeA,
       base::Bind(&DnsProbeRunner::OnTransactionComplete,
                  weak_factory_.GetWeakPtr()),
       BoundNetLog());
 
-  int rv = transaction_->Start();
-  if (rv != net::ERR_IO_PENDING)
-    OnTransactionComplete(transaction_.get(), rv, NULL);
+  transaction_->Start();
 }
 
 bool DnsProbeRunner::IsRunning() const {
diff --git a/chrome/browser/net/dns_probe_runner_unittest.cc b/chrome/browser/net/dns_probe_runner_unittest.cc
index e8568cc..5020afc 100644
--- a/chrome/browser/net/dns_probe_runner_unittest.cc
+++ b/chrome/browser/net/dns_probe_runner_unittest.cc
@@ -15,6 +15,8 @@
 using base::MessageLoopForIO;
 using base::RunLoop;
 using content::TestBrowserThreadBundle;
+using net::DnsClient;
+using net::DnsConfig;
 using net::MockDnsClientRule;
 
 namespace chrome_browser_net {
@@ -77,12 +79,8 @@
   RunTest(MockDnsClientRule::TIMEOUT, DnsProbeRunner::UNREACHABLE);
 }
 
-TEST_F(DnsProbeRunnerTest, Probe_FAIL_ASYNC) {
-  RunTest(MockDnsClientRule::FAIL_ASYNC, DnsProbeRunner::INCORRECT);
-}
-
-TEST_F(DnsProbeRunnerTest, Probe_FAIL_SYNC) {
-  RunTest(MockDnsClientRule::FAIL_SYNC, DnsProbeRunner::INCORRECT);
+TEST_F(DnsProbeRunnerTest, Probe_FAIL) {
+  RunTest(MockDnsClientRule::FAIL, DnsProbeRunner::INCORRECT);
 }
 
 TEST_F(DnsProbeRunnerTest, TwoProbes) {
@@ -90,6 +88,24 @@
   RunTest(MockDnsClientRule::EMPTY, DnsProbeRunner::INCORRECT);
 }
 
+TEST_F(DnsProbeRunnerTest, InvalidDnsConfig) {
+  scoped_ptr<DnsClient> dns_client(DnsClient::CreateClient(NULL));
+  DnsConfig empty_config;
+  dns_client->SetConfig(empty_config);
+  ASSERT_EQ(NULL, dns_client->GetTransactionFactory());
+  runner_.SetClient(dns_client.Pass());
+
+  TestDnsProbeRunnerCallback callback;
+
+  runner_.RunProbe(callback.callback());
+  EXPECT_TRUE(runner_.IsRunning());
+
+  RunLoop().RunUntilIdle();
+  EXPECT_FALSE(runner_.IsRunning());
+  EXPECT_TRUE(callback.called());
+  EXPECT_EQ(DnsProbeRunner::UNKNOWN, runner_.result());
+}
+
 }  // namespace
 
 }  // namespace chrome_browser_net
diff --git a/chrome/browser/net/dns_probe_service_unittest.cc b/chrome/browser/net/dns_probe_service_unittest.cc
index 450426b..946bf9a 100644
--- a/chrome/browser/net/dns_probe_service_unittest.cc
+++ b/chrome/browser/net/dns_probe_service_unittest.cc
@@ -95,18 +95,18 @@
           chrome_common_net::DNS_PROBE_FINISHED_NO_INTERNET);
 }
 
-TEST_F(DnsProbeServiceTest, Probe_OK_FAIL_SYNC) {
-  RunTest(MockDnsClientRule::OK, MockDnsClientRule::FAIL_SYNC,
+TEST_F(DnsProbeServiceTest, Probe_OK_FAIL) {
+  RunTest(MockDnsClientRule::OK, MockDnsClientRule::FAIL,
           chrome_common_net::DNS_PROBE_FINISHED_NXDOMAIN);
 }
 
-TEST_F(DnsProbeServiceTest, Probe_FAIL_SYNC_OK) {
-  RunTest(MockDnsClientRule::FAIL_SYNC, MockDnsClientRule::OK,
+TEST_F(DnsProbeServiceTest, Probe_FAIL_OK) {
+  RunTest(MockDnsClientRule::FAIL, MockDnsClientRule::OK,
           chrome_common_net::DNS_PROBE_FINISHED_BAD_CONFIG);
 }
 
-TEST_F(DnsProbeServiceTest, Probe_FAIL_SYNC_FAIL_SYNC) {
-  RunTest(MockDnsClientRule::FAIL_SYNC, MockDnsClientRule::FAIL_SYNC,
+TEST_F(DnsProbeServiceTest, Probe_FAIL_FAIL) {
+  RunTest(MockDnsClientRule::FAIL, MockDnsClientRule::FAIL,
           chrome_common_net::DNS_PROBE_FINISHED_INCONCLUSIVE);
 }
 
diff --git a/chrome/browser/net/http_server_properties_manager.cc b/chrome/browser/net/http_server_properties_manager.cc
index 7da72f4..c77f624 100644
--- a/chrome/browser/net/http_server_properties_manager.cc
+++ b/chrome/browser/net/http_server_properties_manager.cc
@@ -67,10 +67,14 @@
 }
 
 HttpServerPropertiesManager::~HttpServerPropertiesManager() {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+  io_weak_ptr_factory_.reset();
 }
 
 void HttpServerPropertiesManager::InitializeOnIOThread() {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+  io_weak_ptr_factory_.reset(
+      new base::WeakPtrFactory<HttpServerPropertiesManager>(this));
   http_server_properties_impl_.reset(new net::HttpServerPropertiesImpl());
 
   io_prefs_update_timer_.reset(
@@ -111,6 +115,12 @@
 }
 
 // This is required for conformance with the HttpServerProperties interface.
+base::WeakPtr<net::HttpServerProperties>
+    HttpServerPropertiesManager::GetWeakPtr() {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+  return io_weak_ptr_factory_->GetWeakPtr();
+}
+
 void HttpServerPropertiesManager::Clear() {
   Clear(base::Closure());
 }
diff --git a/chrome/browser/net/http_server_properties_manager.h b/chrome/browser/net/http_server_properties_manager.h
index 756b119..a2a52a7 100644
--- a/chrome/browser/net/http_server_properties_manager.h
+++ b/chrome/browser/net/http_server_properties_manager.h
@@ -81,6 +81,9 @@
   // net::HttpServerProperties methods:
   // ----------------------------------
 
+  // Gets a weak pointer for this object.
+  virtual base::WeakPtr<net::HttpServerProperties> GetWeakPtr() OVERRIDE;
+
   // Deletes all data. Works asynchronously.
   virtual void Clear() OVERRIDE;
 
@@ -229,6 +232,10 @@
   // IO thread
   // ---------
 
+  // Used to get |weak_ptr_| to self on the IO thread.
+  scoped_ptr<base::WeakPtrFactory<HttpServerPropertiesManager> >
+      io_weak_ptr_factory_;
+
   // Used to post |prefs::kHttpServerProperties| pref update tasks.
   scoped_ptr<base::OneShotTimer<HttpServerPropertiesManager> >
       io_prefs_update_timer_;
diff --git a/chrome/browser/net/pref_proxy_config_tracker.cc b/chrome/browser/net/pref_proxy_config_tracker.cc
new file mode 100644
index 0000000..f71f841
--- /dev/null
+++ b/chrome/browser/net/pref_proxy_config_tracker.cc
@@ -0,0 +1,11 @@
+// Copyright 2013 The Chromium Authors. 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/pref_proxy_config_tracker.h"
+
+PrefProxyConfigTracker::PrefProxyConfigTracker() {
+}
+
+PrefProxyConfigTracker::~PrefProxyConfigTracker() {
+}
diff --git a/chrome/browser/net/pref_proxy_config_tracker.h b/chrome/browser/net/pref_proxy_config_tracker.h
index 97dc70e..7ce43e0 100644
--- a/chrome/browser/net/pref_proxy_config_tracker.h
+++ b/chrome/browser/net/pref_proxy_config_tracker.h
@@ -5,18 +5,39 @@
 #ifndef CHROME_BROWSER_NET_PREF_PROXY_CONFIG_TRACKER_H_
 #define CHROME_BROWSER_NET_PREF_PROXY_CONFIG_TRACKER_H_
 
-#include "chrome/browser/net/pref_proxy_config_tracker_impl.h"
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
 
-#if defined(OS_CHROMEOS)
-namespace chromeos {
-class ProxyConfigServiceImpl;
+namespace net {
+class ProxyConfigService;
 }
-#endif  // defined(OS_CHROMEOS)
 
-#if defined(OS_CHROMEOS)
-typedef chromeos::ProxyConfigServiceImpl PrefProxyConfigTracker;
-#else
-typedef PrefProxyConfigTrackerImpl PrefProxyConfigTracker;
-#endif  // defined(OS_CHROMEOS)
+// Interface for a class that tracks proxy preferences. The purpose of the
+// concrete class is to track changes in the Preferences, to translates the
+// preferences to net::ProxyConfig and to push the result over to a
+// net::ProxyConfigService onto the IO thread.
+class PrefProxyConfigTracker {
+ public:
+  PrefProxyConfigTracker();
+  virtual ~PrefProxyConfigTracker();
+
+  // Creates a net::ProxyConfigService and keeps a pointer to it. After this
+  // call, this tracker forwards any changes of proxy preferences to the created
+  // ProxyConfigService. The returned ProxyConfigService must not be deleted
+  // before DetachFromPrefService was called. Takes ownership of the passed
+  // |base_service|, which can be NULL. This |base_service| provides the proxy
+  // settings of the OS (except of ChromeOS). This must be called on the
+  // UI thread.
+  virtual scoped_ptr<net::ProxyConfigService> CreateTrackingProxyConfigService(
+      scoped_ptr<net::ProxyConfigService> base_service) = 0;
+
+  // Releases the PrefService passed upon construction and the |base_service|
+  // passed to CreateTrackingProxyConfigService. This must be called on the UI
+  // thread.
+  virtual void DetachFromPrefService() = 0;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(PrefProxyConfigTracker);
+};
 
 #endif  // CHROME_BROWSER_NET_PREF_PROXY_CONFIG_TRACKER_H_
diff --git a/chrome/browser/net/pref_proxy_config_tracker_impl.cc b/chrome/browser/net/pref_proxy_config_tracker_impl.cc
index 2c6318c..5dd3e5d 100644
--- a/chrome/browser/net/pref_proxy_config_tracker_impl.cc
+++ b/chrome/browser/net/pref_proxy_config_tracker_impl.cc
@@ -140,13 +140,17 @@
   DCHECK(pref_service_ == NULL);
 }
 
-void PrefProxyConfigTrackerImpl::SetChromeProxyConfigService(
-    ChromeProxyConfigService* chrome_proxy_config_service) {
+scoped_ptr<net::ProxyConfigService>
+PrefProxyConfigTrackerImpl::CreateTrackingProxyConfigService(
+    scoped_ptr<net::ProxyConfigService> base_service) {
+  chrome_proxy_config_service_ =
+      new ChromeProxyConfigService(base_service.release());
   VLOG(1) << this << ": set chrome proxy config service to "
-          << chrome_proxy_config_service;
-  chrome_proxy_config_service_ = chrome_proxy_config_service;
+          << chrome_proxy_config_service_;
   if (chrome_proxy_config_service_ && update_pending_)
     OnProxyConfigChanged(config_state_, pref_config_);
+
+  return scoped_ptr<net::ProxyConfigService>(chrome_proxy_config_service_);
 }
 
 void PrefProxyConfigTrackerImpl::DetachFromPrefService() {
@@ -154,7 +158,7 @@
   // Stop notifications.
   proxy_prefs_.RemoveAll();
   pref_service_ = NULL;
-  SetChromeProxyConfigService(NULL);
+  chrome_proxy_config_service_ = NULL;
 }
 
 // static
diff --git a/chrome/browser/net/pref_proxy_config_tracker_impl.h b/chrome/browser/net/pref_proxy_config_tracker_impl.h
index 0abbc99..4e1aa00 100644
--- a/chrome/browser/net/pref_proxy_config_tracker_impl.h
+++ b/chrome/browser/net/pref_proxy_config_tracker_impl.h
@@ -10,6 +10,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/observer_list.h"
 #include "base/prefs/pref_change_registrar.h"
+#include "chrome/browser/net/pref_proxy_config_tracker.h"
 #include "chrome/browser/prefs/proxy_config_dictionary.h"
 #include "net/proxy/proxy_config.h"
 #include "net/proxy/proxy_config_service.h"
@@ -81,18 +82,18 @@
 // A class that tracks proxy preferences. It translates the configuration
 // to net::ProxyConfig and pushes the result over to the IO thread for
 // ChromeProxyConfigService::UpdateProxyConfig to use.
-class PrefProxyConfigTrackerImpl {
+class PrefProxyConfigTrackerImpl : public PrefProxyConfigTracker {
  public:
   explicit PrefProxyConfigTrackerImpl(PrefService* pref_service);
   virtual ~PrefProxyConfigTrackerImpl();
 
-  // Sets the proxy config service to push the preference proxy to.
-  void SetChromeProxyConfigService(
-      ChromeProxyConfigService* proxy_config_service);
+  // PrefProxyConfigTracker implementation:
+  virtual scoped_ptr<net::ProxyConfigService> CreateTrackingProxyConfigService(
+      scoped_ptr<net::ProxyConfigService> base_service) OVERRIDE;
 
   // Notifies the tracker that the pref service passed upon construction is
   // about to go away. This must be called from the UI thread.
-  void DetachFromPrefService();
+  virtual void DetachFromPrefService() OVERRIDE;
 
   // Determines if |config_state| takes precedence regardless, which happens if
   // config is from policy or extension or other-precede.
diff --git a/chrome/browser/net/pref_proxy_config_tracker_impl_unittest.cc b/chrome/browser/net/pref_proxy_config_tracker_impl_unittest.cc
index 1313731..40a9647 100644
--- a/chrome/browser/net/pref_proxy_config_tracker_impl_unittest.cc
+++ b/chrome/browser/net/pref_proxy_config_tracker_impl_unittest.cc
@@ -87,11 +87,10 @@
     delegate_service_ =
         new TestProxyConfigService(fixed_config_,
                                    net::ProxyConfigService::CONFIG_VALID);
-    proxy_config_service_.reset(
-        new ChromeProxyConfigService(delegate_service_));
     proxy_config_tracker_.reset(new PrefProxyConfigTrackerImpl(pref_service));
-    proxy_config_tracker_->SetChromeProxyConfigService(
-        proxy_config_service_.get());
+    proxy_config_service_ =
+        proxy_config_tracker_->CreateTrackingProxyConfigService(
+            scoped_ptr<net::ProxyConfigService>(delegate_service_));
     // SetChromeProxyConfigService triggers update of initial prefs proxy
     // config by tracker to chrome proxy config service, so flush all pending
     // tasks so that tests start fresh.
@@ -107,7 +106,7 @@
 
   base::MessageLoop loop_;
   TestProxyConfigService* delegate_service_; // weak
-  scoped_ptr<ChromeProxyConfigService> proxy_config_service_;
+  scoped_ptr<net::ProxyConfigService> proxy_config_service_;
   net::ProxyConfig fixed_config_;
 
  private:
diff --git a/chrome/browser/net/proxy_service_factory.cc b/chrome/browser/net/proxy_service_factory.cc
index 0c83d0e..ab66107 100644
--- a/chrome/browser/net/proxy_service_factory.cc
+++ b/chrome/browser/net/proxy_service_factory.cc
@@ -9,7 +9,7 @@
 #include "base/threading/thread.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/io_thread.h"
-#include "chrome/browser/net/pref_proxy_config_tracker.h"
+#include "chrome/browser/net/pref_proxy_config_tracker_impl.h"
 #include "chrome/common/chrome_switches.h"
 #include "content/public/browser/browser_thread.h"
 #include "net/base/net_log.h"
@@ -27,12 +27,13 @@
 using content::BrowserThread;
 
 // static
-ChromeProxyConfigService* ProxyServiceFactory::CreateProxyConfigService() {
+net::ProxyConfigService* ProxyServiceFactory::CreateProxyConfigService(
+    PrefProxyConfigTracker* tracker) {
   // The linux gconf-based proxy settings getter relies on being initialized
   // from the UI thread.
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 
-  net::ProxyConfigService* base_service = NULL;
+  scoped_ptr<net::ProxyConfigService> base_service;
 
 #if !defined(OS_CHROMEOS)
   // On ChromeOS, base service is NULL; chromeos::ProxyConfigServiceImpl
@@ -46,12 +47,13 @@
   // TODO(port): the IO and FILE message loops are only used by Linux.  Can
   // that code be moved to chrome/browser instead of being in net, so that it
   // can use BrowserThread instead of raw MessageLoop pointers? See bug 25354.
-  base_service = net::ProxyService::CreateSystemProxyConfigService(
+  base_service.reset(net::ProxyService::CreateSystemProxyConfigService(
       BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO).get(),
-      BrowserThread::UnsafeGetMessageLoopForThread(BrowserThread::FILE));
+      BrowserThread::UnsafeGetMessageLoopForThread(BrowserThread::FILE)));
 #endif  // !defined(OS_CHROMEOS)
 
-  return new ChromeProxyConfigService(base_service);
+  return tracker->CreateTrackingProxyConfigService(base_service.Pass())
+      .release();
 }
 
 // static
diff --git a/chrome/browser/net/proxy_service_factory.h b/chrome/browser/net/proxy_service_factory.h
index 154f5e9..f16e226 100644
--- a/chrome/browser/net/proxy_service_factory.h
+++ b/chrome/browser/net/proxy_service_factory.h
@@ -7,38 +7,24 @@
 
 #include "base/basictypes.h"
 
-class ChromeProxyConfigService;
 class CommandLine;
-class PrefProxyConfigTrackerImpl;
+class PrefProxyConfigTracker;
 class PrefService;
 
-#if defined(OS_CHROMEOS)
-namespace chromeos {
-class ProxyConfigServiceImpl;
-}
-#endif  // defined(OS_CHROMEOS)
-
-#if defined(OS_CHROMEOS)
-typedef chromeos::ProxyConfigServiceImpl PrefProxyConfigTracker;
-#else
-typedef PrefProxyConfigTrackerImpl PrefProxyConfigTracker;
-#endif  // defined(OS_CHROMEOS)
-
 namespace net {
 class NetLog;
 class NetworkDelegate;
 class ProxyConfigService;
 class ProxyService;
 class URLRequestContext;
-}  // namespace net
+}
 
 class ProxyServiceFactory {
  public:
   // Creates a ProxyConfigService that delivers the system preferences
   // (or the respective ChromeOS equivalent).
-  // The ChromeProxyConfigService returns "pending" until it has been informed
-  // about the proxy configuration by calling its UpdateProxyConfig method.
-  static ChromeProxyConfigService* CreateProxyConfigService();
+  static net::ProxyConfigService* CreateProxyConfigService(
+      PrefProxyConfigTracker* tracker);
 
   // Creates a PrefProxyConfigTracker that tracks preferences of a
   // profile. On ChromeOS it additionaly tracks local state for shared proxy
diff --git a/chrome/browser/net/resource_prefetch_predictor_observer.h b/chrome/browser/net/resource_prefetch_predictor_observer.h
index 5ffb27b..3790f0a 100644
--- a/chrome/browser/net/resource_prefetch_predictor_observer.h
+++ b/chrome/browser/net/resource_prefetch_predictor_observer.h
@@ -8,7 +8,7 @@
 #include "base/basictypes.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/predictors/resource_prefetch_predictor.h"
-#include "webkit/glue/resource_type.h"
+#include "webkit/common/resource_type.h"
 
 namespace net {
 class URLRequest;
diff --git a/chrome/browser/notifications/balloon.cc b/chrome/browser/notifications/balloon.cc
index 2a73c05..0997212 100644
--- a/chrome/browser/notifications/balloon.cc
+++ b/chrome/browser/notifications/balloon.cc
@@ -82,9 +82,9 @@
 }
 
 std::string Balloon::GetExtensionId() {
-  const ExtensionURLInfo url(notification().origin_url());
   const ExtensionService* service = profile()->GetExtensionService();
   const extensions::Extension* extension =
-      service->extensions()->GetExtensionOrAppByURL(url);
+      service->extensions()->GetExtensionOrAppByURL(
+          notification().origin_url());
   return extension ? extension->id() : std::string();
 }
diff --git a/chrome/browser/notifications/balloon_collection_impl.h b/chrome/browser/notifications/balloon_collection_impl.h
index 07b223d..45b26d0 100644
--- a/chrome/browser/notifications/balloon_collection_impl.h
+++ b/chrome/browser/notifications/balloon_collection_impl.h
@@ -12,7 +12,7 @@
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
 #include "base/memory/weak_ptr.h"
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "chrome/browser/notifications/balloon_collection.h"
 #include "chrome/browser/notifications/balloon_collection_base.h"
 #include "content/public/browser/notification_observer.h"
diff --git a/chrome/browser/notifications/desktop_notification_service.cc b/chrome/browser/notifications/desktop_notification_service.cc
index e81a2b1..90c827b 100644
--- a/chrome/browser/notifications/desktop_notification_service.cc
+++ b/chrome/browser/notifications/desktop_notification_service.cc
@@ -42,7 +42,6 @@
 #include "grit/generated_resources.h"
 #include "grit/theme_resources.h"
 #include "net/base/escape.h"
-#include "third_party/WebKit/public/web/WebSecurityOrigin.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/message_center/message_center_util.h"
@@ -55,7 +54,6 @@
 using message_center::NotifierId;
 using WebKit::WebNotificationPresenter;
 using WebKit::WebTextDirection;
-using WebKit::WebSecurityOrigin;
 
 
 // NotificationPermissionInfoBarDelegate --------------------------------------
@@ -64,7 +62,7 @@
 // permissions.
 class NotificationPermissionInfoBarDelegate : public ConfirmInfoBarDelegate {
  public:
-  // Creates a notification permission delegate and adds it to
+  // Creates a notification permission infobar delegate and adds it to
   // |infobar_service|.
   static void Create(InfoBarService* infobar_service,
                      DesktopNotificationService* notification_service,
diff --git a/chrome/browser/notifications/desktop_notification_service_unittest.cc b/chrome/browser/notifications/desktop_notification_service_unittest.cc
index a4ec7b1..5b48097 100644
--- a/chrome/browser/notifications/desktop_notification_service_unittest.cc
+++ b/chrome/browser/notifications/desktop_notification_service_unittest.cc
@@ -6,7 +6,7 @@
 
 #include "base/bind.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "base/synchronization/waitable_event.h"
 #include "chrome/browser/notifications/desktop_notification_service_factory.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
diff --git a/chrome/browser/notifications/desktop_notifications_unittest.cc b/chrome/browser/notifications/desktop_notifications_unittest.cc
index 7b969f3..9d07c8b 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 "third_party/WebKit/public/web/WebKit.h"
 #include "ui/aura/env.h"
 #include "ui/aura/root_window.h"
 #include "ui/compositor/scoped_animation_duration_scale_mode.h"
@@ -103,7 +102,6 @@
 void DesktopNotificationsTest::SetUp() {
   ui::InitializeInputMethodForTesting();
 #if defined(USE_ASH)
-  WebKit::initialize(webkit_platform_support_.Get());
   ui::ScopedAnimationDurationScaleMode normal_duration_mode(
       ui::ScopedAnimationDurationScaleMode::ZERO_DURATION);
   // The message center is notmally initialized on |g_browser_process| which
@@ -133,7 +131,6 @@
   // is not created for these tests.
   message_center::MessageCenter::Shutdown();
   aura::Env::DeleteInstance();
-  WebKit::shutdown();
 #endif
   ui::ShutdownInputMethodForTesting();
 }
diff --git a/chrome/browser/notifications/desktop_notifications_unittest.h b/chrome/browser/notifications/desktop_notifications_unittest.h
index ad8d0d8..935710f 100644
--- a/chrome/browser/notifications/desktop_notifications_unittest.h
+++ b/chrome/browser/notifications/desktop_notifications_unittest.h
@@ -8,7 +8,7 @@
 #include <deque>
 #include <string>
 
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "base/prefs/testing_pref_service.h"
 #include "chrome/browser/notifications/balloon_collection_impl.h"
 #include "chrome/browser/notifications/balloon_notification_ui_manager.h"
@@ -114,11 +114,6 @@
   // Real DesktopNotificationService
   scoped_ptr<DesktopNotificationService> service_;
 
-#if defined(USE_ASH)
-  content::RenderViewTest::RendererWebKitPlatformSupportImplNoSandbox
-      webkit_platform_support_;
-#endif
-
   // Contains the cumulative output of the unit test.
   static std::string log_output_;
 };
diff --git a/chrome/browser/notifications/message_center_notifications_browsertest.cc b/chrome/browser/notifications/message_center_notifications_browsertest.cc
index 4cd7ce7..455f514 100644
--- a/chrome/browser/notifications/message_center_notifications_browsertest.cc
+++ b/chrome/browser/notifications/message_center_notifications_browsertest.cc
@@ -5,7 +5,7 @@
 #include <string>
 
 #include "base/command_line.h"
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
@@ -21,6 +21,10 @@
 #include "ui/message_center/message_center_switches.h"
 #include "ui/message_center/message_center_util.h"
 
+#if defined(OS_WIN) && defined(USE_ASH)
+#include "base/win/windows_version.h"
+#endif
+
 class TestAddObserver : public message_center::MessageCenterObserver {
  public:
   TestAddObserver(const std::string& id,
@@ -177,6 +181,12 @@
 #endif
 
 IN_PROC_BROWSER_TEST_F(MessageCenterNotificationsTest, MAYBE_BasicDelegate) {
+#if defined(OS_WIN) && defined(USE_ASH)
+  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
+  if (base::win::GetVersion() >= base::win::VERSION_WIN8)
+    return;
+#endif
+
   EXPECT_TRUE(NotificationUIManager::DelegatesToMessageCenter());
   TestDelegate* delegate;
   manager()->Add(CreateTestNotification("hey", &delegate), profile());
@@ -197,6 +207,12 @@
 
 IN_PROC_BROWSER_TEST_F(MessageCenterNotificationsTest,
                        MAYBE_ButtonClickedDelegate) {
+#if defined(OS_WIN) && defined(USE_ASH)
+  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
+  if (base::win::GetVersion() >= base::win::VERSION_WIN8)
+    return;
+#endif
+
   EXPECT_TRUE(NotificationUIManager::DelegatesToMessageCenter());
   TestDelegate* delegate;
   manager()->Add(CreateTestNotification("n", &delegate), profile());
@@ -215,6 +231,12 @@
 
 IN_PROC_BROWSER_TEST_F(MessageCenterNotificationsTest,
                        MAYBE_UpdateExistingNotification) {
+#if defined(OS_WIN) && defined(USE_ASH)
+  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
+  if (base::win::GetVersion() >= base::win::VERSION_WIN8)
+    return;
+#endif
+
   EXPECT_TRUE(NotificationUIManager::DelegatesToMessageCenter());
   TestDelegate* delegate;
   manager()->Add(CreateTestNotification("n", &delegate), profile());
diff --git a/chrome/browser/notifications/notification_options_menu_model.cc b/chrome/browser/notifications/notification_options_menu_model.cc
index 3d2cbea..7a11a1a 100644
--- a/chrome/browser/notifications/notification_options_menu_model.cc
+++ b/chrome/browser/notifications/notification_options_menu_model.cc
@@ -140,8 +140,7 @@
     ExtensionService* extension_service =
         balloon_->profile()->GetExtensionService();
     const extensions::Extension* extension =
-        extension_service->extensions()->GetExtensionOrAppByURL(
-            ExtensionURLInfo(origin));
+        extension_service->extensions()->GetExtensionOrAppByURL(origin);
     // We get back no extension here when we show the notification after
     // the extension has crashed.
     if (extension) {
@@ -192,8 +191,7 @@
       ExtensionService* extension_service =
           balloon_->profile()->GetExtensionService();
       const extensions::Extension* extension =
-          extension_service->extensions()->GetExtensionOrAppByURL(
-              ExtensionURLInfo(origin));
+          extension_service->extensions()->GetExtensionOrAppByURL(origin);
       if (extension) {
         return l10n_util::GetStringUTF16(
             extension_service->IsExtensionEnabled(extension->id()) ?
@@ -251,8 +249,7 @@
       break;
     case kToggleExtensionCommand: {
       const extensions::Extension* extension =
-          extension_service->extensions()->GetExtensionOrAppByURL(
-              ExtensionURLInfo(origin));
+          extension_service->extensions()->GetExtensionOrAppByURL(origin);
       if (extension) {
         const std::string& id = extension->id();
         if (extension_service->IsExtensionEnabled(id))
diff --git a/chrome/browser/notifications/sync_notifier/synced_notification_unittest.cc b/chrome/browser/notifications/sync_notifier/synced_notification_unittest.cc
index abb60a2..ccd6b4f 100644
--- a/chrome/browser/notifications/sync_notifier/synced_notification_unittest.cc
+++ b/chrome/browser/notifications/sync_notifier/synced_notification_unittest.cc
@@ -5,7 +5,7 @@
 #include <string>
 
 #include "base/memory/scoped_ptr.h"
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/notifications/notification.h"
 #include "chrome/browser/notifications/notification_test_util.h"
diff --git a/chrome/browser/page_cycler/page_cycler.cc b/chrome/browser/page_cycler/page_cycler.cc
index 1f1c47e..7fcf078 100644
--- a/chrome/browser/page_cycler/page_cycler.cc
+++ b/chrome/browser/page_cycler/page_cycler.cc
@@ -7,7 +7,7 @@
 #include "base/bind.h"
 #include "base/file_util.h"
 #include "base/files/file_path.h"
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
 #include "base/process_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
diff --git a/chrome/browser/password_manager/login_database.cc b/chrome/browser/password_manager/login_database.cc
index 9b0ebda..7204385 100644
--- a/chrome/browser/password_manager/login_database.cc
+++ b/chrome/browser/password_manager/login_database.cc
@@ -83,6 +83,22 @@
   return found_port == form_port;
 }
 
+bool IsPublicSuffixDomainMatchingEnabled() {
+#if defined(OS_ANDROID)
+  if (CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kEnablePasswordAutofillPublicSuffixDomainMatching)) {
+    return true;
+  }
+  if (CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kDisablePasswordAutofillPublicSuffixDomainMatching)) {
+    return false;
+  }
+  return true;
+#else
+  return false;
+#endif
+}
+
 }  // namespace
 
 LoginDatabase::LoginDatabase() : public_suffix_domain_matching_(false) {
@@ -140,8 +156,7 @@
     return false;
   }
 
-  public_suffix_domain_matching_ = CommandLine::ForCurrentProcess()->HasSwitch(
-      switches::kEnablePasswordAutofillPublicSuffixDomainMatching);
+  public_suffix_domain_matching_ = IsPublicSuffixDomainMatchingEnabled();
 
   return true;
 }
diff --git a/chrome/browser/password_manager/password_manager.cc b/chrome/browser/password_manager/password_manager.cc
index 15bfb8c..e1390aa 100644
--- a/chrome/browser/password_manager/password_manager.cc
+++ b/chrome/browser/password_manager/password_manager.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/password_manager/password_manager.h"
 
+#include "base/command_line.h"
 #include "base/metrics/field_trial.h"
 #include "base/metrics/histogram.h"
 #include "base/prefs/pref_service.h"
@@ -13,6 +14,7 @@
 #include "chrome/browser/password_manager/password_form_manager.h"
 #include "chrome/browser/password_manager/password_manager_delegate.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/common/chrome_switches.h"
 #include "chrome/common/chrome_version_info.h"
 #include "chrome/common/pref_names.h"
 #include "components/autofill/core/common/autofill_messages.h"
@@ -308,12 +310,16 @@
   provisional_save_manager_->SubmitPassed();
   if (provisional_save_manager_->HasGeneratedPassword())
     UMA_HISTOGRAM_COUNTS("PasswordGeneration.Submitted", 1);
-  if (ShouldShowSavePasswordInfoBar()) {
-    delegate_->AddSavePasswordInfoBarIfPermitted(
-        provisional_save_manager_.release());
-  } else {
-    provisional_save_manager_->Save();
-    provisional_save_manager_.reset();
+
+  if(!CommandLine::ForCurrentProcess()->HasSwitch(
+      switches::kEnableSavePasswordBubble)){
+    if (ShouldShowSavePasswordInfoBar()) {
+      delegate_->AddSavePasswordInfoBarIfPermitted(
+          provisional_save_manager_.release());
+    } else {
+      provisional_save_manager_->Save();
+      provisional_save_manager_.reset();
+    }
   }
 }
 
diff --git a/chrome/browser/password_manager/password_manager_delegate_impl.cc b/chrome/browser/password_manager/password_manager_delegate_impl.cc
index edf7a23..95ce6b8 100644
--- a/chrome/browser/password_manager/password_manager_delegate_impl.cc
+++ b/chrome/browser/password_manager/password_manager_delegate_impl.cc
@@ -40,7 +40,8 @@
 class SavePasswordInfoBarDelegate : public ConfirmInfoBarDelegate {
  public:
   // If we won't be showing the one-click signin infobar, creates a save
-  // password delegate and adds it to the InfoBarService for |web_contents|.
+  // password infobar delegate and adds it to the InfoBarService for
+  // |web_contents|.
   static void Create(content::WebContents* web_contents,
                      PasswordFormManager* form_to_save);
 
diff --git a/chrome/browser/password_manager/password_store_unittest.cc b/chrome/browser/password_manager/password_store_unittest.cc
index 0c179b6..25d177e 100644
--- a/chrome/browser/password_manager/password_store_unittest.cc
+++ b/chrome/browser/password_manager/password_store_unittest.cc
@@ -152,7 +152,7 @@
       true, true, cutoff - 1 },
     // A form on https://www.google.com/ older than the cutoff. Will be ignored.
     { PasswordForm::SCHEME_HTML,
-      "https://www.google.com/",
+      "https://www.google.com",
       "https://www.google.com/origin",
       "https://www.google.com/action",
       L"submit_element",
diff --git a/chrome/browser/pepper_broker_infobar_delegate.cc b/chrome/browser/pepper_broker_infobar_delegate.cc
index 66624ec..9ca7068 100644
--- a/chrome/browser/pepper_broker_infobar_delegate.cc
+++ b/chrome/browser/pepper_broker_infobar_delegate.cc
@@ -17,11 +17,11 @@
 #include "content/public/browser/user_metrics.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/referrer.h"
+#include "content/public/common/webplugininfo.h"
 #include "grit/generated_resources.h"
 #include "grit/theme_resources.h"
 #include "net/base/net_util.h"
 #include "ui/base/l10n/l10n_util.h"
-#include "webkit/plugins/webplugininfo.h"
 
 #if defined(GOOGLE_TV)
 #include "base/android/context_types.h"
@@ -48,11 +48,12 @@
 #if defined(OS_CHROMEOS)
   // On ChromeOS, we're ok with granting broker access to the Netflix and
   // Widevine plugins, since they can only come installed with the OS.
-  const char kNetflixPluginFileName[] = "libnetflixplugin2.so";
   const char kWidevinePluginFileName[] = "libwidevinecdmadapter.so";
+  const char kNetflixDomain[] = "netflix.com";
+
   base::FilePath plugin_file_name = plugin_path.BaseName();
-  if (plugin_file_name.value() == FILE_PATH_LITERAL(kNetflixPluginFileName) ||
-      plugin_file_name.value() == FILE_PATH_LITERAL(kWidevinePluginFileName)) {
+  if (plugin_file_name.value() == FILE_PATH_LITERAL(kWidevinePluginFileName) &&
+      url.DomainIs(kNetflixDomain)) {
     tab_content_settings->SetPepperBrokerAllowed(true);
     callback.Run(true);
     return;
@@ -139,7 +140,7 @@
 string16 PepperBrokerInfoBarDelegate::GetMessageText() const {
   content::PluginService* plugin_service =
       content::PluginService::GetInstance();
-  webkit::WebPluginInfo plugin;
+  content::WebPluginInfo plugin;
   bool success = plugin_service->GetPluginInfoByPath(plugin_path_, &plugin);
   DCHECK(success);
   scoped_ptr<PluginMetadata> plugin_metadata(
diff --git a/chrome/browser/pepper_broker_infobar_delegate.h b/chrome/browser/pepper_broker_infobar_delegate.h
index 33574d1..220297c 100644
--- a/chrome/browser/pepper_broker_infobar_delegate.h
+++ b/chrome/browser/pepper_broker_infobar_delegate.h
@@ -25,7 +25,7 @@
  public:
   // Determines whether the broker setting is allow, deny, or ask.  In the first
   // two cases, runs the callback directly.  In the third, creates a pepper
-  // broker delegate and adds it to the InfoBarService associated with
+  // broker infobar delegate and adds it to the InfoBarService associated with
   // |web_contents|.
   static void Create(content::WebContents* web_contents,
                      const GURL& url,
diff --git a/chrome/browser/pepper_flash_settings_manager.cc b/chrome/browser/pepper_flash_settings_manager.cc
index 2886b4e..243ea84 100644
--- a/chrome/browser/pepper_flash_settings_manager.cc
+++ b/chrome/browser/pepper_flash_settings_manager.cc
@@ -24,12 +24,12 @@
 #include "content/public/browser/pepper_flash_settings_helper.h"
 #include "content/public/browser/plugin_service.h"
 #include "content/public/common/content_constants.h"
+#include "content/public/common/webplugininfo.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"
 
 using content::BrowserThread;
 
@@ -401,7 +401,7 @@
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
   DCHECK_EQ(STATE_UNINITIALIZED, state_);
 
-  webkit::WebPluginInfo plugin_info;
+  content::WebPluginInfo plugin_info;
   if (!PepperFlashSettingsManager::IsPepperFlashInUse(plugin_prefs_.get(),
                                                       &plugin_info)) {
     NotifyErrorFromIOThread();
@@ -947,19 +947,19 @@
 // static
 bool PepperFlashSettingsManager::IsPepperFlashInUse(
     PluginPrefs* plugin_prefs,
-    webkit::WebPluginInfo* plugin_info) {
+    content::WebPluginInfo* plugin_info) {
   if (!plugin_prefs)
     return false;
 
   content::PluginService* plugin_service =
       content::PluginService::GetInstance();
-  std::vector<webkit::WebPluginInfo> plugins;
+  std::vector<content::WebPluginInfo> plugins;
   plugin_service->GetPluginInfoArray(
       GURL(), kFlashPluginSwfMimeType, false, &plugins, NULL);
 
-  for (std::vector<webkit::WebPluginInfo>::iterator iter = plugins.begin();
+  for (std::vector<content::WebPluginInfo>::iterator iter = plugins.begin();
        iter != plugins.end(); ++iter) {
-    if (webkit::IsPepperPlugin(*iter) && plugin_prefs->IsPluginEnabled(*iter)) {
+    if (iter->is_pepper_plugin() && plugin_prefs->IsPluginEnabled(*iter)) {
       if (plugin_info)
         *plugin_info = *iter;
       return true;
diff --git a/chrome/browser/pepper_flash_settings_manager.h b/chrome/browser/pepper_flash_settings_manager.h
index cefb9c5..6aef457 100644
--- a/chrome/browser/pepper_flash_settings_manager.h
+++ b/chrome/browser/pepper_flash_settings_manager.h
@@ -16,16 +16,13 @@
 
 namespace content {
 class BrowserContext;
+struct WebPluginInfo;
 }
 
 namespace user_prefs {
 class PrefRegistrySyncable;
 }
 
-namespace webkit {
-struct WebPluginInfo;
-}
-
 // PepperFlashSettingsManager communicates with a PPAPI broker process to
 // read/write Pepper Flash settings.
 class PepperFlashSettingsManager {
@@ -64,7 +61,7 @@
   // |plugin_info| will be updated if it is not NULL and the method returns
   // true.
   static bool IsPepperFlashInUse(PluginPrefs* plugin_prefs,
-                                 webkit::WebPluginInfo* plugin_info);
+                                 content::WebPluginInfo* plugin_info);
 
   static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
 
diff --git a/chrome/browser/plugins/chrome_plugin_service_filter.cc b/chrome/browser/plugins/chrome_plugin_service_filter.cc
index 633d758..c466380 100644
--- a/chrome/browser/plugins/chrome_plugin_service_filter.cc
+++ b/chrome/browser/plugins/chrome_plugin_service_filter.cc
@@ -42,7 +42,7 @@
     int render_process_id,
     int render_view_id,
     const GURL& url,
-    const webkit::WebPluginInfo& plugin) {
+    const content::WebPluginInfo& plugin) {
   base::AutoLock auto_lock(lock_);
   ProcessDetails* details = GetOrRegisterProcess(render_process_id);
   OverriddenPlugin overridden_plugin;
@@ -73,7 +73,7 @@
     const void* context,
     const GURL& url,
     const GURL& policy_url,
-    webkit::WebPluginInfo* plugin) {
+    content::WebPluginInfo* plugin) {
   base::AutoLock auto_lock(lock_);
   const ProcessDetails* details = GetProcess(render_process_id);
 
diff --git a/chrome/browser/plugins/chrome_plugin_service_filter.h b/chrome/browser/plugins/chrome_plugin_service_filter.h
index 5b61c3a..513b1ff 100644
--- a/chrome/browser/plugins/chrome_plugin_service_filter.h
+++ b/chrome/browser/plugins/chrome_plugin_service_filter.h
@@ -17,8 +17,8 @@
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
 #include "content/public/browser/plugin_service_filter.h"
+#include "content/public/common/webplugininfo.h"
 #include "url/gurl.h"
-#include "webkit/plugins/webplugininfo.h"
 
 class PluginPrefs;
 class Profile;
@@ -40,7 +40,7 @@
   void OverridePluginForTab(int render_process_id,
                             int render_view_id,
                             const GURL& url,
-                            const webkit::WebPluginInfo& plugin);
+                            const content::WebPluginInfo& plugin);
 
   // Restricts the given plugin to the given profile and origin of the given
   // URL.
@@ -65,7 +65,7 @@
       const void* context,
       const GURL& url,
       const GURL& policy_url,
-      webkit::WebPluginInfo* plugin) OVERRIDE;
+      content::WebPluginInfo* plugin) OVERRIDE;
 
   // CanLoadPlugin always grants permission to the browser
   // (render_process_id == 0)
@@ -82,7 +82,7 @@
 
     int render_view_id;
     GURL url;  // If empty, the override applies to all urls in render_view.
-    webkit::WebPluginInfo plugin;
+    content::WebPluginInfo plugin;
   };
 
   struct ProcessDetails {
diff --git a/chrome/browser/plugins/plugin_data_remover_helper.cc b/chrome/browser/plugins/plugin_data_remover_helper.cc
index f9e19ae..0f7d6b7 100644
--- a/chrome/browser/plugins/plugin_data_remover_helper.cc
+++ b/chrome/browser/plugins/plugin_data_remover_helper.cc
@@ -6,13 +6,13 @@
 
 #include "chrome/browser/plugins/plugin_prefs.h"
 #include "content/public/browser/plugin_data_remover.h"
-#include "webkit/plugins/webplugininfo.h"
+#include "content/public/common/webplugininfo.h"
 
 // static
 bool PluginDataRemoverHelper::IsSupported(PluginPrefs* plugin_prefs) {
-  std::vector<webkit::WebPluginInfo> plugins;
+  std::vector<content::WebPluginInfo> plugins;
   content::PluginDataRemover::GetSupportedPlugins(&plugins);
-  for (std::vector<webkit::WebPluginInfo>::const_iterator it = plugins.begin();
+  for (std::vector<content::WebPluginInfo>::const_iterator it = plugins.begin();
        it != plugins.end(); ++it) {
     if (plugin_prefs->IsPluginEnabled(*it))
       return true;
diff --git a/chrome/browser/plugins/plugin_finder.cc b/chrome/browser/plugins/plugin_finder.cc
index 5cf9378..9f7b799 100644
--- a/chrome/browser/plugins/plugin_finder.cc
+++ b/chrome/browser/plugins/plugin_finder.cc
@@ -34,18 +34,18 @@
 typedef std::map<std::string, PluginMetadata*> PluginMap;
 
 // Gets the full path of the plug-in file as the identifier.
-std::string GetLongIdentifier(const webkit::WebPluginInfo& plugin) {
+std::string GetLongIdentifier(const content::WebPluginInfo& plugin) {
   return plugin.path.AsUTF8Unsafe();
 }
 
 // Gets the base name of the file path as the identifier.
-std::string GetIdentifier(const webkit::WebPluginInfo& plugin) {
+std::string GetIdentifier(const content::WebPluginInfo& plugin) {
   return plugin.path.BaseName().AsUTF8Unsafe();
 }
 
 // Gets the plug-in group name as the plug-in name if it is not empty or
 // the filename without extension if the name is empty.
-static string16 GetGroupName(const webkit::WebPluginInfo& plugin) {
+static string16 GetGroupName(const content::WebPluginInfo& plugin) {
   if (!plugin.name.empty())
     return plugin.name;
 
@@ -277,7 +277,7 @@
 }
 
 scoped_ptr<PluginMetadata> PluginFinder::GetPluginMetadata(
-    const webkit::WebPluginInfo& plugin) {
+    const content::WebPluginInfo& plugin) {
   base::AutoLock lock(mutex_);
   for (PluginMap::const_iterator it = identifier_plugin_.begin();
        it != identifier_plugin_.end(); ++it) {
diff --git a/chrome/browser/plugins/plugin_finder.h b/chrome/browser/plugins/plugin_finder.h
index 25e1eee..d7f8cb0 100644
--- a/chrome/browser/plugins/plugin_finder.h
+++ b/chrome/browser/plugins/plugin_finder.h
@@ -14,7 +14,7 @@
 #include "base/memory/singleton.h"
 #include "base/strings/string16.h"
 #include "base/synchronization/lock.h"
-#include "webkit/plugins/webplugininfo.h"
+#include "content/public/common/webplugininfo.h"
 
 namespace base {
 class DictionaryValue;
@@ -65,7 +65,7 @@
 
   // Gets plug-in metadata using |plugin|.
   scoped_ptr<PluginMetadata> GetPluginMetadata(
-      const webkit::WebPluginInfo& plugin);
+      const content::WebPluginInfo& plugin);
 
  private:
   friend struct DefaultSingletonTraits<PluginFinder>;
diff --git a/chrome/browser/plugins/plugin_info_message_filter.cc b/chrome/browser/plugins/plugin_info_message_filter.cc
index 399a01f..f2260e4 100644
--- a/chrome/browser/plugins/plugin_info_message_filter.cc
+++ b/chrome/browser/plugins/plugin_info_message_filter.cc
@@ -31,7 +31,7 @@
 #endif
 
 using content::PluginService;
-using webkit::WebPluginInfo;
+using content::WebPluginInfo;
 
 namespace {
 
diff --git a/chrome/browser/plugins/plugin_info_message_filter.h b/chrome/browser/plugins/plugin_info_message_filter.h
index 9eaafe1..d57427e 100644
--- a/chrome/browser/plugins/plugin_info_message_filter.h
+++ b/chrome/browser/plugins/plugin_info_message_filter.h
@@ -25,9 +25,6 @@
 
 namespace content {
 class ResourceContext;
-}
-
-namespace webkit {
 struct WebPluginInfo;
 }
 
@@ -46,7 +43,7 @@
 
     void DecidePluginStatus(
         const GetPluginInfo_Params& params,
-        const webkit::WebPluginInfo& plugin,
+        const content::WebPluginInfo& plugin,
         const PluginMetadata* plugin_metadata,
         ChromeViewHostMsg_GetPluginInfo_Status* status) const;
     bool FindEnabledPlugin(int render_view_id,
@@ -54,10 +51,10 @@
                            const GURL& top_origin_url,
                            const std::string& mime_type,
                            ChromeViewHostMsg_GetPluginInfo_Status* status,
-                           webkit::WebPluginInfo* plugin,
+                           content::WebPluginInfo* plugin,
                            std::string* actual_mime_type,
                            scoped_ptr<PluginMetadata>* plugin_metadata) const;
-    void GetPluginContentSetting(const webkit::WebPluginInfo& plugin,
+    void GetPluginContentSetting(const content::WebPluginInfo& plugin,
                                  const GURL& policy_url,
                                  const GURL& plugin_url,
                                  const std::string& resource,
@@ -99,7 +96,7 @@
   // |base::Bind| doesn't support the required arity <http://crbug.com/98542>.
   void PluginsLoaded(const GetPluginInfo_Params& params,
                      IPC::Message* reply_msg,
-                     const std::vector<webkit::WebPluginInfo>& plugins);
+                     const std::vector<content::WebPluginInfo>& plugins);
 
   Context context_;
 
diff --git a/chrome/browser/plugins/plugin_infobar_delegates.cc b/chrome/browser/plugins/plugin_infobar_delegates.cc
index 2ad36c7..e4a2651 100644
--- a/chrome/browser/plugins/plugin_infobar_delegates.cc
+++ b/chrome/browser/plugins/plugin_infobar_delegates.cc
@@ -172,6 +172,8 @@
     InfoBarService* infobar_service,
     PluginInstaller* installer,
     scoped_ptr<PluginMetadata> plugin_metadata) {
+  // Copy the name out of |plugin_metadata| now, since the Pass() call below
+  // will make it impossible to get at.
   string16 name(plugin_metadata->name());
   infobar_service->AddInfoBar(scoped_ptr<InfoBarDelegate>(
       new OutdatedPluginInfoBarDelegate(
@@ -293,9 +295,7 @@
   // Return early if the message doesn't change. This is important in case the
   // PluginInstaller is still iterating over its observers (otherwise we would
   // keep replacing infobar delegates infinitely).
-  if (message_ == message)
-    return;
-  if (!owner())
+  if ((message_ == message) || !owner())
     return;
   PluginInstallerInfoBarDelegate::Replace(
       this, installer(), plugin_metadata_->Clone(), false, message);
@@ -396,7 +396,6 @@
     url = google_util::AppendGoogleLocaleParam(GURL(
         "https://www.google.com/support/chrome/bin/answer.py?answer=142064"));
   }
-
   web_contents()->OpenURL(content::OpenURLParams(
       url, content::Referrer(),
       (disposition == CURRENT_TAB) ? NEW_FOREGROUND_TAB : disposition,
@@ -436,9 +435,7 @@
   // Return early if the message doesn't change. This is important in case the
   // PluginInstaller is still iterating over its observers (otherwise we would
   // keep replacing infobar delegates infinitely).
-  if (message_ == message)
-    return;
-  if (!owner())
+  if ((message_ == message) || !owner())
     return;
   Replace(this, installer(), plugin_metadata_->Clone(), new_install_, message);
 }
diff --git a/chrome/browser/plugins/plugin_infobar_delegates.h b/chrome/browser/plugins/plugin_infobar_delegates.h
index 72ab27c..35a064c 100644
--- a/chrome/browser/plugins/plugin_infobar_delegates.h
+++ b/chrome/browser/plugins/plugin_infobar_delegates.h
@@ -23,11 +23,9 @@
 
 // Base class for blocked plug-in infobars.
 class PluginInfoBarDelegate : public ConfirmInfoBarDelegate {
- public:
+ protected:
   PluginInfoBarDelegate(InfoBarService* infobar_service,
                         const std::string& identifier);
-
- protected:
   virtual ~PluginInfoBarDelegate();
 
   // ConfirmInfoBarDelegate:
@@ -50,7 +48,8 @@
 // Infobar that's shown when a plug-in requires user authorization to run.
 class UnauthorizedPluginInfoBarDelegate : public PluginInfoBarDelegate {
  public:
-  // Creates an unauthorized plugin delegate and adds it to |infobar_service|.
+  // Creates an unauthorized plugin infobar delegate and adds it to
+  // |infobar_service|.
   static void Create(InfoBarService* infobar_service,
                      HostContentSettingsMap* content_settings,
                      const string16& name,
@@ -83,7 +82,8 @@
 class OutdatedPluginInfoBarDelegate : public PluginInfoBarDelegate,
                                       public WeakPluginInstallerObserver {
  public:
-  // Creates an outdated plugin delegate and adds it to |infobar_service|.
+  // Creates an outdated plugin infobar delegate and adds it to
+  // |infobar_service|.
   static void Create(InfoBarService* infobar_service,
                      PluginInstaller* installer,
                      scoped_ptr<PluginMetadata> metadata);
@@ -144,7 +144,7 @@
   // the user to install or update a particular plugin.
   static void Replace(InfoBarDelegate* infobar,
                       PluginInstaller* installer,
-                      scoped_ptr<PluginMetadata> metadata,
+                      scoped_ptr<PluginMetadata> plugin_metadata,
                       bool new_install,
                       const string16& message);
 
diff --git a/chrome/browser/plugins/plugin_installer.h b/chrome/browser/plugins/plugin_installer.h
index 36a4261..978fe1a 100644
--- a/chrome/browser/plugins/plugin_installer.h
+++ b/chrome/browser/plugins/plugin_installer.h
@@ -18,9 +18,6 @@
 
 namespace content {
 class WebContents;
-}
-
-namespace webkit {
 struct WebPluginInfo;
 }
 
diff --git a/chrome/browser/plugins/plugin_installer_unittest.cc b/chrome/browser/plugins/plugin_installer_unittest.cc
index 9fd2e41..bceecc4 100644
--- a/chrome/browser/plugins/plugin_installer_unittest.cc
+++ b/chrome/browser/plugins/plugin_installer_unittest.cc
@@ -5,19 +5,18 @@
 #include "chrome/browser/plugins/plugin_installer.h"
 
 #include "base/strings/utf_string_conversions.h"
+#include "content/public/common/webplugininfo.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "webkit/plugins/webplugininfo.h"
-
-using webkit::WebPluginInfo;
 
 namespace {
 
 PluginInstaller::SecurityStatus GetSecurityStatus(PluginInstaller* installer,
                                                   const char* version) {
-  WebPluginInfo plugin(ASCIIToUTF16("Foo plug-in"),
-                       base::FilePath(FILE_PATH_LITERAL("/tmp/plugin.so")),
-                       ASCIIToUTF16(version),
-                       ASCIIToUTF16("Foo plug-in."));
+  content:: WebPluginInfo plugin(
+      ASCIIToUTF16("Foo plug-in"),
+      base::FilePath(FILE_PATH_LITERAL("/tmp/plugin.so")),
+      ASCIIToUTF16(version),
+      ASCIIToUTF16("Foo plug-in."));
   return installer->GetSecurityStatus(plugin);
 }
 
diff --git a/chrome/browser/plugins/plugin_metadata.cc b/chrome/browser/plugins/plugin_metadata.cc
index ce64531..5f2fc50 100644
--- a/chrome/browser/plugins/plugin_metadata.cc
+++ b/chrome/browser/plugins/plugin_metadata.cc
@@ -8,8 +8,7 @@
 
 #include "base/logging.h"
 #include "base/strings/string_util.h"
-#include "webkit/plugins/npapi/plugin_utils.h"
-#include "webkit/plugins/webplugininfo.h"
+#include "content/public/common/webplugininfo.h"
 
 // static
 const char PluginMetadata::kAdobeReaderGroupName[] = "Adobe Reader";
@@ -59,7 +58,7 @@
       all_mime_types_.end();
 }
 
-bool PluginMetadata::MatchesPlugin(const webkit::WebPluginInfo& plugin) {
+bool PluginMetadata::MatchesPlugin(const content::WebPluginInfo& plugin) {
   for (size_t i = 0; i < matching_mime_types_.size(); ++i) {
     // To have a match, every one of the |matching_mime_types_|
     // must be handled by the plug-in.
@@ -92,7 +91,7 @@
 }
 
 PluginMetadata::SecurityStatus PluginMetadata::GetSecurityStatus(
-    const webkit::WebPluginInfo& plugin) const {
+    const content::WebPluginInfo& plugin) const {
   if (versions_.empty()) {
 #if defined(OS_LINUX)
     // On Linux, unknown plugins require authorization.
@@ -103,7 +102,7 @@
   }
 
   Version version;
-  webkit::npapi::CreateVersionFromString(plugin.version, &version);
+  content::WebPluginInfo::CreateVersionFromString(plugin.version, &version);
   if (!version.IsValid())
     version = Version("0");
 
diff --git a/chrome/browser/plugins/plugin_metadata.h b/chrome/browser/plugins/plugin_metadata.h
index 69019a7..98d1925 100644
--- a/chrome/browser/plugins/plugin_metadata.h
+++ b/chrome/browser/plugins/plugin_metadata.h
@@ -12,7 +12,7 @@
 #include "base/version.h"
 #include "url/gurl.h"
 
-namespace webkit {
+namespace content {
 struct WebPluginInfo;
 }
 
@@ -72,7 +72,7 @@
   // Checks if |plugin| mime types match all |matching_mime_types_|.
   // If there is no |matching_mime_types_|, |group_name_matcher_| is used
   // for matching.
-  bool MatchesPlugin(const webkit::WebPluginInfo& plugin);
+  bool MatchesPlugin(const content::WebPluginInfo& plugin);
 
   // If |status_str| describes a valid security status, writes it to |status|
   // and returns true, else returns false and leaves |status| unchanged.
@@ -81,7 +81,7 @@
 
   // Returns the security status for the given plug-in (i.e. whether it is
   // considered out-of-date, etc.)
-  SecurityStatus GetSecurityStatus(const webkit::WebPluginInfo& plugin) const;
+  SecurityStatus GetSecurityStatus(const content::WebPluginInfo& plugin) const;
 
   scoped_ptr<PluginMetadata> Clone() const;
 
diff --git a/chrome/browser/plugins/plugin_metadata_unittest.cc b/chrome/browser/plugins/plugin_metadata_unittest.cc
index 0ff692c..bb69ee7 100644
--- a/chrome/browser/plugins/plugin_metadata_unittest.cc
+++ b/chrome/browser/plugins/plugin_metadata_unittest.cc
@@ -5,20 +5,19 @@
 #include "chrome/browser/plugins/plugin_metadata.h"
 
 #include "base/strings/utf_string_conversions.h"
+#include "content/public/common/webplugininfo.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "webkit/plugins/webplugininfo.h"
-
-using webkit::WebPluginInfo;
 
 namespace {
 
 PluginMetadata::SecurityStatus GetSecurityStatus(
     PluginMetadata* plugin_metadata,
     const char* version) {
-  WebPluginInfo plugin(ASCIIToUTF16("Foo plug-in"),
-                       base::FilePath(FILE_PATH_LITERAL("/tmp/plugin.so")),
-                       ASCIIToUTF16(version),
-                       ASCIIToUTF16("Foo plug-in."));
+  content::WebPluginInfo plugin(
+      ASCIIToUTF16("Foo plug-in"),
+      base::FilePath(FILE_PATH_LITERAL("/tmp/plugin.so")),
+      ASCIIToUTF16(version),
+      ASCIIToUTF16("Foo plug-in."));
   return plugin_metadata->GetSecurityStatus(plugin);
 }
 
diff --git a/chrome/browser/plugins/plugin_observer.cc b/chrome/browser/plugins/plugin_observer.cc
index a6a64a2..7c9cd67 100644
--- a/chrome/browser/plugins/plugin_observer.cc
+++ b/chrome/browser/plugins/plugin_observer.cc
@@ -29,10 +29,10 @@
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_delegate.h"
 #include "content/public/browser/web_contents_view.h"
+#include "content/public/common/webplugininfo.h"
 #include "grit/generated_resources.h"
 #include "grit/theme_resources.h"
 #include "ui/base/l10n/l10n_util.h"
-#include "webkit/plugins/webplugininfo.h"
 
 #if defined(ENABLE_PLUGIN_INSTALLATION)
 #if defined(OS_WIN)
@@ -83,8 +83,7 @@
     content::WebContents* web_contents,
     PluginInstaller* installer,
     scoped_ptr<PluginMetadata> plugin_metadata)
-    : TabModalConfirmDialogDelegate(web_contents),
-      WeakPluginInstallerObserver(installer),
+    : WeakPluginInstallerObserver(installer),
       web_contents_(web_contents),
       plugin_metadata_(plugin_metadata.Pass()) {
 }
@@ -404,7 +403,7 @@
 
   scoped_ptr<PluginMetadata> plugin;
   bool ret = PluginFinder::GetInstance()->FindPluginWithIdentifier(
-          identifier, NULL, &plugin);
+      identifier, NULL, &plugin);
   DCHECK(ret);
 
   PluginMetroModeInfoBarDelegate::Create(
diff --git a/chrome/browser/plugins/plugin_prefs.cc b/chrome/browser/plugins/plugin_prefs.cc
index 37841ca..a88e151 100644
--- a/chrome/browser/plugins/plugin_prefs.cc
+++ b/chrome/browser/plugins/plugin_prefs.cc
@@ -31,7 +31,7 @@
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/plugin_service.h"
-#include "webkit/plugins/webplugininfo.h"
+#include "content/public/common/webplugininfo.h"
 
 using content::BrowserThread;
 using content::PluginService;
@@ -110,7 +110,7 @@
 void PluginPrefs::EnablePluginGroupInternal(
     bool enabled,
     const string16& group_name,
-    const std::vector<webkit::WebPluginInfo>& plugins) {
+    const std::vector<content::WebPluginInfo>& plugins) {
   base::AutoLock auto_lock(lock_);
   PluginFinder* finder = PluginFinder::GetInstance();
 
@@ -135,7 +135,7 @@
     bool enabled, const base::FilePath& path,
     const base::Callback<void(bool)>& callback) {
   PluginFinder* finder = PluginFinder::GetInstance();
-  webkit::WebPluginInfo plugin;
+  content::WebPluginInfo plugin;
   bool can_enable = true;
   if (PluginService::GetInstance()->GetPluginInfoByPath(path, &plugin)) {
     scoped_ptr<PluginMetadata> plugin_metadata(
@@ -169,7 +169,7 @@
     const base::FilePath& path,
     PluginFinder* plugin_finder,
     const base::Callback<void(bool)>& callback,
-    const std::vector<webkit::WebPluginInfo>& plugins) {
+    const std::vector<content::WebPluginInfo>& plugins) {
   {
     // Set the desired state for the plug-in.
     base::AutoLock auto_lock(lock_);
@@ -225,7 +225,7 @@
   }
 }
 
-bool PluginPrefs::IsPluginEnabled(const webkit::WebPluginInfo& plugin) const {
+bool PluginPrefs::IsPluginEnabled(const content::WebPluginInfo& plugin) const {
   scoped_ptr<PluginMetadata> plugin_metadata(
       PluginFinder::GetInstance()->GetPluginMetadata(plugin));
   string16 group_name = plugin_metadata->name();
@@ -522,7 +522,7 @@
 }
 
 void PluginPrefs::OnUpdatePreferences(
-    const std::vector<webkit::WebPluginInfo>& plugins) {
+    const std::vector<content::WebPluginInfo>& plugins) {
   if (!prefs_)
     return;
 
diff --git a/chrome/browser/plugins/plugin_prefs.h b/chrome/browser/plugins/plugin_prefs.h
index fd0e403..bfcaa06 100644
--- a/chrome/browser/plugins/plugin_prefs.h
+++ b/chrome/browser/plugins/plugin_prefs.h
@@ -23,7 +23,7 @@
 class ListValue;
 }
 
-namespace webkit {
+namespace content {
 struct WebPluginInfo;
 }
 
@@ -70,7 +70,7 @@
   PolicyStatus PolicyStatusForPlugin(const string16& name) const;
 
   // Returns whether the plugin is enabled or not.
-  bool IsPluginEnabled(const webkit::WebPluginInfo& plugin) const;
+  bool IsPluginEnabled(const content::WebPluginInfo& plugin) const;
 
   void set_profile(Profile* profile) { profile_ = profile; }
 
@@ -117,16 +117,16 @@
   void EnablePluginGroupInternal(
       bool enabled,
       const string16& group_name,
-      const std::vector<webkit::WebPluginInfo>& plugins);
+      const std::vector<content::WebPluginInfo>& plugins);
   void EnablePluginInternal(
       bool enabled,
       const base::FilePath& path,
       PluginFinder* plugin_finder,
       const base::Callback<void(bool)>& callback,
-      const std::vector<webkit::WebPluginInfo>& plugins);
+      const std::vector<content::WebPluginInfo>& plugins);
 
   // Called on the UI thread with the plugin data to save the preferences.
-  void OnUpdatePreferences(const std::vector<webkit::WebPluginInfo>& plugins);
+  void OnUpdatePreferences(const std::vector<content::WebPluginInfo>& plugins);
 
   // Sends the notification that plugin data has changed.
   void NotifyPluginStatusChanged();
diff --git a/chrome/browser/plugins/plugin_prefs_unittest.cc b/chrome/browser/plugins/plugin_prefs_unittest.cc
index 18863c8..53e148d 100644
--- a/chrome/browser/plugins/plugin_prefs_unittest.cc
+++ b/chrome/browser/plugins/plugin_prefs_unittest.cc
@@ -13,10 +13,11 @@
 #include "chrome/common/chrome_constants.h"
 #include "chrome/common/chrome_paths.h"
 #include "content/public/browser/plugin_service.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/common/webplugininfo.h"
 #include "content/public/test/test_browser_thread.h"
+#include "content/public/test/test_utils.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "webkit/plugins/npapi/mock_plugin_list.h"
-#include "webkit/plugins/webplugininfo.h"
 
 using content::BrowserThread;
 using content::PluginService;
@@ -46,6 +47,11 @@
   return path;
 }
 
+void GotPlugins(const base::Closure& quit_closure,
+                const std::vector<content::WebPluginInfo>& plugins) {
+  quit_closure.Run();
+}
+
 }  // namespace
 
 class PluginPrefsTest : public ::testing::Test {
@@ -177,35 +183,52 @@
             plugin_prefs_->PolicyStatusForPlugin(k42));
 }
 
+// Linux Aura doesn't support NPAPI.
+#if !(defined(OS_LINUX) && defined(USE_AURA))
+
 TEST_F(PluginPrefsTest, UnifiedPepperFlashState) {
   base::ShadowingAtExitManager at_exit_manager_;  // Destroys the PluginService.
 
   base::MessageLoop message_loop;
   content::TestBrowserThread ui_thread(BrowserThread::UI, &message_loop);
-  webkit::npapi::MockPluginList plugin_list;
-  PluginService::GetInstance()->SetPluginListForTesting(&plugin_list);
   PluginService::GetInstance()->Init();
+  PluginService::GetInstance()->DisablePluginsDiscoveryForTesting();
 
   string16 component_updated_plugin_name(
       ASCIIToUTF16("Component-updated Pepper Flash"));
-  webkit::WebPluginInfo component_updated_plugin_1(
+  content::WebPluginInfo component_updated_plugin_1(
       component_updated_plugin_name,
       GetComponentUpdatedPepperFlashPath(FILE_PATH_LITERAL("11.3.31.227")),
       ASCIIToUTF16("11.3.31.227"),
       ASCIIToUTF16(""));
-  webkit::WebPluginInfo component_updated_plugin_2(
+  content::WebPluginInfo component_updated_plugin_2(
       component_updated_plugin_name,
       GetComponentUpdatedPepperFlashPath(FILE_PATH_LITERAL("11.3.31.228")),
       ASCIIToUTF16("11.3.31.228"),
       ASCIIToUTF16(""));
-  webkit::WebPluginInfo bundled_plugin(ASCIIToUTF16("Pepper Flash"),
-                                       GetBundledPepperFlashPath(),
-                                       ASCIIToUTF16("11.3.31.229"),
-                                       ASCIIToUTF16(""));
+  content::WebPluginInfo bundled_plugin(ASCIIToUTF16("Pepper Flash"),
+                                        GetBundledPepperFlashPath(),
+                                        ASCIIToUTF16("11.3.31.229"),
+                                        ASCIIToUTF16(""));
 
-  plugin_list.AddPluginToLoad(component_updated_plugin_1);
-  plugin_list.AddPluginToLoad(component_updated_plugin_2);
-  plugin_list.AddPluginToLoad(bundled_plugin);
+  PluginService::GetInstance()->RegisterInternalPlugin(
+      component_updated_plugin_1, false);
+  PluginService::GetInstance()->RegisterInternalPlugin(
+      component_updated_plugin_2, false);
+  PluginService::GetInstance()->RegisterInternalPlugin(bundled_plugin, false);
+
+#if !defined(OS_WIN)
+    // Can't go out of process in unit tests.
+    content::RenderProcessHost::SetRunRendererInProcess(true);
+#endif
+  scoped_refptr<content::MessageLoopRunner> runner =
+      new content::MessageLoopRunner;
+  PluginService::GetInstance()->GetPlugins(
+      base::Bind(&GotPlugins, runner->QuitClosure()));
+  runner->Run();
+#if !defined(OS_WIN)
+    content::RenderProcessHost::SetRunRendererInProcess(false);
+#endif
 
   // Set the state of any of the three plugins will affect the others.
   EnablePluginSynchronously(true, component_updated_plugin_1.path, true);
@@ -249,6 +272,6 @@
   EXPECT_FALSE(plugin_prefs_->IsPluginEnabled(component_updated_plugin_1));
   EXPECT_FALSE(plugin_prefs_->IsPluginEnabled(component_updated_plugin_2));
   EXPECT_TRUE(plugin_prefs_->IsPluginEnabled(bundled_plugin));
-
-  PluginService::GetInstance()->SetPluginListForTesting(NULL);
 }
+
+#endif
diff --git a/chrome/browser/plugins/plugin_status_pref_setter.cc b/chrome/browser/plugins/plugin_status_pref_setter.cc
index 09bf546..f2b4e7f 100644
--- a/chrome/browser/plugins/plugin_status_pref_setter.cc
+++ b/chrome/browser/plugins/plugin_status_pref_setter.cc
@@ -15,7 +15,7 @@
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/notification_source.h"
 #include "content/public/browser/plugin_service.h"
-#include "webkit/plugins/webplugininfo.h"
+#include "content/public/common/webplugininfo.h"
 
 using content::BrowserThread;
 using content::PluginService;
@@ -59,7 +59,7 @@
 
 void PluginStatusPrefSetter::GotPlugins(
     scoped_refptr<PluginPrefs> plugin_prefs,
-    const std::vector<webkit::WebPluginInfo>& /* plugins */) {
+    const std::vector<content::WebPluginInfo>& plugins) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   // Set the values on the PrefService instead of through the PrefMembers to
   // notify observers if they changed.
diff --git a/chrome/browser/plugins/plugin_status_pref_setter.h b/chrome/browser/plugins/plugin_status_pref_setter.h
index 034b74a..e77c94a 100644
--- a/chrome/browser/plugins/plugin_status_pref_setter.h
+++ b/chrome/browser/plugins/plugin_status_pref_setter.h
@@ -17,7 +17,7 @@
 class PrefService;
 class Profile;
 
-namespace webkit {
+namespace content {
 struct WebPluginInfo;
 }
 
@@ -53,7 +53,7 @@
  private:
   void StartUpdate();
   void GotPlugins(scoped_refptr<PluginPrefs> plugin_prefs,
-                  const std::vector<webkit::WebPluginInfo>& plugins);
+                  const std::vector<content::WebPluginInfo>& plugins);
 
   content::NotificationRegistrar registrar_;
   // Weak pointer.
diff --git a/chrome/browser/policy/browser_policy_connector.cc b/chrome/browser/policy/browser_policy_connector.cc
index 718e572..2a1d1cf 100644
--- a/chrome/browser/policy/browser_policy_connector.cc
+++ b/chrome/browser/policy/browser_policy_connector.cc
@@ -37,7 +37,7 @@
 #include "grit/generated_resources.h"
 #include "net/url_request/url_request_context_getter.h"
 #include "policy/policy_constants.h"
-#include "third_party/icu/public/i18n/unicode/regex.h"
+#include "third_party/icu/source/i18n/unicode/regex.h"
 
 #if defined(OS_WIN)
 #include "chrome/browser/policy/policy_loader_win.h"
diff --git a/chrome/browser/policy/cloud/cloud_policy_client.cc b/chrome/browser/policy/cloud/cloud_policy_client.cc
index 3581d31..a9b30c3 100644
--- a/chrome/browser/policy/cloud/cloud_policy_client.cc
+++ b/chrome/browser/policy/cloud/cloud_policy_client.cc
@@ -34,7 +34,7 @@
 
 bool IsChromePolicy(const std::string& type) {
   return type == dm_protocol::kChromeDevicePolicyType ||
-         type == dm_protocol::kChromeUserPolicyType;
+         type == GetChromeUserPolicyType();
 }
 
 }  // namespace
diff --git a/chrome/browser/policy/cloud/cloud_policy_constants.cc b/chrome/browser/policy/cloud/cloud_policy_constants.cc
index 905ddab..83f05f4 100644
--- a/chrome/browser/policy/cloud/cloud_policy_constants.cc
+++ b/chrome/browser/policy/cloud/cloud_policy_constants.cc
@@ -4,6 +4,9 @@
 
 #include "chrome/browser/policy/cloud/cloud_policy_constants.h"
 
+#include "base/command_line.h"
+#include "chrome/common/chrome_switches.h"
+
 namespace policy {
 
 // Constants related to the device management protocol.
@@ -32,10 +35,10 @@
 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";
+#elif defined(OS_ANDROID)
+const char kChromeUserPolicyType[] = "google/android/user";
 #else
 const char kChromeUserPolicyType[] = "google/chrome/user";
 #endif
@@ -44,4 +47,13 @@
 
 }  // namespace dm_protocol
 
+const char* GetChromeUserPolicyType() {
+#if defined(OS_ANDROID)
+  CommandLine* command_line = CommandLine::ForCurrentProcess();
+  if (command_line->HasSwitch(switches::kFakeCloudPolicyType))
+    return "google/chrome/user";
+#endif
+  return dm_protocol::kChromeUserPolicyType;
+}
+
 }  // namespace policy
diff --git a/chrome/browser/policy/cloud/cloud_policy_constants.h b/chrome/browser/policy/cloud/cloud_policy_constants.h
index 028d9c9..a0fb70b 100644
--- a/chrome/browser/policy/cloud/cloud_policy_constants.h
+++ b/chrome/browser/policy/cloud/cloud_policy_constants.h
@@ -104,6 +104,12 @@
 // A pair that combines a policy fetch type and entity ID.
 typedef std::pair<std::string, std::string> PolicyNamespaceKey;
 
+// Returns the Chrome user policy type to use. This allows overridding the
+// default user policy type on Android for testing purposes.
+// TODO(joaodasilva): remove this once the server is ready.
+// http://crbug.com/248527
+const char* GetChromeUserPolicyType();
+
 }  // namespace policy
 
 #endif  // CHROME_BROWSER_POLICY_CLOUD_CLOUD_POLICY_CONSTANTS_H_
diff --git a/chrome/browser/policy/cloud/user_cloud_policy_manager.cc b/chrome/browser/policy/cloud/user_cloud_policy_manager.cc
index edaf8be..09db701 100644
--- a/chrome/browser/policy/cloud/user_cloud_policy_manager.cc
+++ b/chrome/browser/policy/cloud/user_cloud_policy_manager.cc
@@ -21,7 +21,7 @@
     Profile* profile,
     scoped_ptr<UserCloudPolicyStore> store)
     : CloudPolicyManager(
-          PolicyNamespaceKey(dm_protocol::kChromeUserPolicyType, std::string()),
+          PolicyNamespaceKey(GetChromeUserPolicyType(), std::string()),
           store.get()),
       profile_(profile),
       store_(store.Pass()) {
diff --git a/chrome/browser/policy/cloud/user_cloud_policy_store_base.cc b/chrome/browser/policy/cloud/user_cloud_policy_store_base.cc
index c875bc7..5d88574 100644
--- a/chrome/browser/policy/cloud/user_cloud_policy_store_base.cc
+++ b/chrome/browser/policy/cloud/user_cloud_policy_store_base.cc
@@ -25,7 +25,7 @@
   // Configure the validator.
   UserCloudPolicyValidator* validator =
       UserCloudPolicyValidator::Create(policy.Pass());
-  validator->ValidatePolicyType(dm_protocol::kChromeUserPolicyType);
+  validator->ValidatePolicyType(GetChromeUserPolicyType());
   validator->ValidateAgainstCurrentPolicy(
       policy_.get(),
       CloudPolicyValidatorBase::TIMESTAMP_REQUIRED,
diff --git a/chrome/browser/policy/cloud/user_policy_signin_service_android.cc b/chrome/browser/policy/cloud/user_policy_signin_service_android.cc
index 93564e7..f165796 100644
--- a/chrome/browser/policy/cloud/user_policy_signin_service_android.cc
+++ b/chrome/browser/policy/cloud/user_policy_signin_service_android.cc
@@ -7,6 +7,7 @@
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/callback.h"
+#include "base/command_line.h"
 #include "base/logging.h"
 #include "base/message_loop/message_loop.h"
 #include "base/prefs/pref_service.h"
@@ -18,11 +19,23 @@
 #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/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
 #include "net/base/network_change_notifier.h"
 
 namespace policy {
 
+namespace {
+
+enterprise_management::DeviceRegisterRequest::Type GetRegistrationType() {
+  CommandLine* command_line = CommandLine::ForCurrentProcess();
+  if (command_line->HasSwitch(switches::kFakeCloudPolicyType))
+    return enterprise_management::DeviceRegisterRequest::BROWSER;
+  return enterprise_management::DeviceRegisterRequest::ANDROID_BROWSER;
+}
+
+}  // namespace
+
 UserPolicySigninService::UserPolicySigninService(Profile* profile)
     : UserPolicySigninServiceBase(profile),
       weak_factory_(this) {}
@@ -43,14 +56,12 @@
 
   // 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));
+      GetRegistrationType()));
   registration_helper_->StartRegistration(
       ProfileOAuth2TokenServiceFactory::GetForProfile(profile()),
       username,
@@ -132,14 +143,12 @@
   profile()->GetPrefs()->SetInt64(prefs::kLastPolicyCheckTime,
                                   base::Time::Now().ToInternalValue());
 
-  // 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(),
       GetManager()->core()->client(),
       force_load_policy,
-      enterprise_management::DeviceRegisterRequest::BROWSER));
+      GetRegistrationType()));
   registration_helper_->StartRegistration(
       ProfileOAuth2TokenServiceFactory::GetForProfile(profile()),
       username,
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 b9402b3..82539a3 100644
--- a/chrome/browser/policy/cloud/user_policy_signin_service_unittest.cc
+++ b/chrome/browser/policy/cloud/user_policy_signin_service_unittest.cc
@@ -98,8 +98,7 @@
 
 class FakeProfileOAuth2TokenService : public AndroidProfileOAuth2TokenService {
  public:
-  explicit FakeProfileOAuth2TokenService(Profile* profile)
-      : AndroidProfileOAuth2TokenService(profile->GetRequestContext()) {
+  explicit FakeProfileOAuth2TokenService(Profile* profile) {
     Initialize(profile);
   }
 
diff --git a/chrome/browser/policy/policy_browsertest.cc b/chrome/browser/policy/policy_browsertest.cc
index 87f9f7e..869c9bf 100644
--- a/chrome/browser/policy/policy_browsertest.cc
+++ b/chrome/browser/policy/policy_browsertest.cc
@@ -95,6 +95,7 @@
 #include "content/public/common/page_transition_types.h"
 #include "content/public/common/process_type.h"
 #include "content/public/common/url_constants.h"
+#include "content/public/common/webplugininfo.h"
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/download_test_observer.h"
 #include "content/public/test/mock_notification_observer.h"
@@ -116,9 +117,7 @@
 #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"
 
 #if defined(OS_CHROMEOS)
 #include "ash/accelerators/accelerator_controller.h"
@@ -132,6 +131,10 @@
 #include "chromeos/audio/audio_pref_handler.h"
 #endif
 
+#if defined(OS_WIN) && defined(USE_ASH)
+#include "base/win/windows_version.h"
+#endif
+
 using content::BrowserThread;
 using content::URLRequestMockHTTPJob;
 using testing::AnyNumber;
@@ -335,8 +338,8 @@
   return result == 123;
 }
 
-void CopyPluginListAndQuit(std::vector<webkit::WebPluginInfo>* out,
-                           const std::vector<webkit::WebPluginInfo>& in) {
+void CopyPluginListAndQuit(std::vector<content::WebPluginInfo>* out,
+                           const std::vector<content::WebPluginInfo>& in) {
   *out = in;
   base::MessageLoop::current()->QuitWhenIdle();
 }
@@ -347,15 +350,15 @@
   base::MessageLoop::current()->QuitWhenIdle();
 }
 
-void GetPluginList(std::vector<webkit::WebPluginInfo>* plugins) {
+void GetPluginList(std::vector<content::WebPluginInfo>* plugins) {
   content::PluginService* service = content::PluginService::GetInstance();
   service->GetPlugins(base::Bind(CopyPluginListAndQuit, plugins));
   content::RunMessageLoop();
 }
 
-const webkit::WebPluginInfo* GetFlashPlugin(
-    const std::vector<webkit::WebPluginInfo>& plugins) {
-  const webkit::WebPluginInfo* flash = NULL;
+const content::WebPluginInfo* GetFlashPlugin(
+    const std::vector<content::WebPluginInfo>& plugins) {
+  const content::WebPluginInfo* flash = NULL;
   for (size_t i = 0; i < plugins.size(); ++i) {
     if (plugins[i].name == ASCIIToUTF16(kFlashPluginName)) {
       flash = &plugins[i];
@@ -373,7 +376,7 @@
 }
 
 bool SetPluginEnabled(PluginPrefs* plugin_prefs,
-                      const webkit::WebPluginInfo* plugin,
+                      const content::WebPluginInfo* plugin,
                       bool enabled) {
   bool ok = false;
   plugin_prefs->EnablePlugin(enabled, plugin->path,
@@ -657,6 +660,12 @@
 #endif
 
 IN_PROC_BROWSER_TEST_F(PolicyTest, BookmarkBarEnabled) {
+#if defined(OS_WIN) && defined(USE_ASH)
+  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
+  if (base::win::GetVersion() >= base::win::VERSION_WIN8)
+    return;
+#endif
+
   // Verifies that the bookmarks bar can be forced to always or never show up.
 
   // Test starts in about:blank.
@@ -927,7 +936,7 @@
   ui_test_utils::SendToOmniboxAndSubmit(location_bar,
       "https://www.google.com/?espv=1#q=foobar");
   EXPECT_TRUE(
-      browser()->toolbar_model()->WouldReplaceSearchURLWithSearchTerms());
+      browser()->toolbar_model()->WouldReplaceSearchURLWithSearchTerms(false));
   EXPECT_EQ(ASCIIToUTF16("foobar"),
             location_bar->GetLocationEntry()->GetText());
 
@@ -937,7 +946,7 @@
   ui_test_utils::SendToOmniboxAndSubmit(location_bar,
       "https://www.google.com/?q=foobar");
   EXPECT_FALSE(
-      browser()->toolbar_model()->WouldReplaceSearchURLWithSearchTerms());
+      browser()->toolbar_model()->WouldReplaceSearchURLWithSearchTerms(false));
   EXPECT_EQ(ASCIIToUTF16("https://www.google.com/?q=foobar"),
             location_bar->GetLocationEntry()->GetText());
 
@@ -947,7 +956,7 @@
   ui_test_utils::SendToOmniboxAndSubmit(location_bar,
       "https://www.google.com/search?espv=1#q=banana");
   EXPECT_TRUE(
-      browser()->toolbar_model()->WouldReplaceSearchURLWithSearchTerms());
+      browser()->toolbar_model()->WouldReplaceSearchURLWithSearchTerms(false));
   EXPECT_EQ(ASCIIToUTF16("banana"),
             location_bar->GetLocationEntry()->GetText());
 
@@ -957,7 +966,7 @@
   ui_test_utils::SendToOmniboxAndSubmit(location_bar,
       "https://www.google.com/search?q=tractor+parts&espv=1");
   EXPECT_TRUE(
-      browser()->toolbar_model()->WouldReplaceSearchURLWithSearchTerms());
+      browser()->toolbar_model()->WouldReplaceSearchURLWithSearchTerms(false));
   EXPECT_EQ(ASCIIToUTF16("tractor parts"),
             location_bar->GetLocationEntry()->GetText());
 
@@ -966,7 +975,7 @@
   ui_test_utils::SendToOmniboxAndSubmit(location_bar,
       "https://www.google.com/search?q=tractor+parts&espv=1#q=foobar");
   EXPECT_TRUE(
-      browser()->toolbar_model()->WouldReplaceSearchURLWithSearchTerms());
+      browser()->toolbar_model()->WouldReplaceSearchURLWithSearchTerms(false));
   EXPECT_EQ(ASCIIToUTF16("foobar"),
             location_bar->GetLocationEntry()->GetText());
 }
@@ -1021,9 +1030,9 @@
 
   // Verify that the Flash plugin exists and that it can be enabled and disabled
   // by the user.
-  std::vector<webkit::WebPluginInfo> plugins;
+  std::vector<content::WebPluginInfo> plugins;
   GetPluginList(&plugins);
-  const webkit::WebPluginInfo* flash = GetFlashPlugin(plugins);
+  const content::WebPluginInfo* flash = GetFlashPlugin(plugins);
   if (!flash)
     return;
   PluginPrefs* plugin_prefs =
@@ -1052,9 +1061,9 @@
 
   // Verify that the Flash plugin exists and that it can be enabled and disabled
   // by the user.
-  std::vector<webkit::WebPluginInfo> plugins;
+  std::vector<content::WebPluginInfo> plugins;
   GetPluginList(&plugins);
-  const webkit::WebPluginInfo* flash = GetFlashPlugin(plugins);
+  const content::WebPluginInfo* flash = GetFlashPlugin(plugins);
   if (!flash)
     return;
   PluginPrefs* plugin_prefs =
@@ -1091,9 +1100,9 @@
 
 IN_PROC_BROWSER_TEST_F(PolicyTest, EnabledPlugins) {
   // Verifies that a plugin can be force-installed with a policy.
-  std::vector<webkit::WebPluginInfo> plugins;
+  std::vector<content::WebPluginInfo> plugins;
   GetPluginList(&plugins);
-  const webkit::WebPluginInfo* flash = GetFlashPlugin(plugins);
+  const content::WebPluginInfo* flash = GetFlashPlugin(plugins);
   if (!flash)
     return;
   PluginPrefs* plugin_prefs =
@@ -1190,6 +1199,12 @@
 }
 
 IN_PROC_BROWSER_TEST_F(PolicyTest, WebStoreIconHidden) {
+#if defined(OS_WIN) && defined(USE_ASH)
+  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
+  if (base::win::GetVersion() >= base::win::VERSION_WIN8)
+    return;
+#endif
+
   // Verifies that the web store icons can be hidden from the new tab page.
 
   // Open new tab page and look for the web store icons.
@@ -1473,6 +1488,12 @@
 }
 
 IN_PROC_BROWSER_TEST_F(PolicyTest, HomepageLocation) {
+#if defined(OS_WIN) && defined(USE_ASH)
+  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
+  if (base::win::GetVersion() >= base::win::VERSION_WIN8)
+    return;
+#endif
+
   // Verifies that the homepage can be configured with policies.
   // Set a default, and check that the home button navigates there.
   browser()->profile()->GetPrefs()->SetString(
@@ -1636,16 +1657,16 @@
 
   // Verify that the translate infobar showed up.
   ASSERT_EQ(1u, infobar_service->infobar_count());
-  InfoBarDelegate* infobar_delegate = infobar_service->infobar_at(0);
-  TranslateInfoBarDelegate* delegate =
-      infobar_delegate->AsTranslateInfoBarDelegate();
-  ASSERT_TRUE(delegate);
+  InfoBarDelegate* infobar = infobar_service->infobar_at(0);
+  TranslateInfoBarDelegate* translate_infobar_delegate =
+      infobar->AsTranslateInfoBarDelegate();
+  ASSERT_TRUE(translate_infobar_delegate);
   EXPECT_EQ(TranslateInfoBarDelegate::BEFORE_TRANSLATE,
-            delegate->infobar_type());
-  EXPECT_EQ("fr", delegate->original_language_code());
+            translate_infobar_delegate->infobar_type());
+  EXPECT_EQ("fr", translate_infobar_delegate->original_language_code());
 
   // Now force disable translate.
-  infobar_service->RemoveInfoBar(infobar_delegate);
+  infobar_service->RemoveInfoBar(infobar);
   EXPECT_EQ(0u, infobar_service->infobar_count());
   policies.Set(key::kTranslateEnabled, POLICY_LEVEL_MANDATORY,
                POLICY_SCOPE_USER, base::Value::CreateBooleanValue(false), NULL);
diff --git a/chrome/browser/predictors/autocomplete_action_predictor.cc b/chrome/browser/predictors/autocomplete_action_predictor.cc
index 5a1e75b..2b9e732 100644
--- a/chrome/browser/predictors/autocomplete_action_predictor.cc
+++ b/chrome/browser/predictors/autocomplete_action_predictor.cc
@@ -138,7 +138,7 @@
 
 void AutocompleteActionPredictor::StartPrerendering(
     const GURL& url,
-    content::SessionStorageNamespace* session_storage_namespace,
+    const content::SessionStorageNamespaceMap& session_storage_namespace_map,
     const gfx::Size& size) {
   // Only cancel the old prerender after starting the new one, so if the URLs
   // are the same, the underlying prerender will be reused.
@@ -146,6 +146,11 @@
       prerender_handle_.release());
   if (prerender::PrerenderManager* prerender_manager =
           prerender::PrerenderManagerFactory::GetForProfile(profile_)) {
+    content::SessionStorageNamespace* session_storage_namespace = NULL;
+    content::SessionStorageNamespaceMap::const_iterator it =
+        session_storage_namespace_map.find(std::string());
+    if (it != session_storage_namespace_map.end())
+      session_storage_namespace = it->second.get();
     prerender_handle_.reset(prerender_manager->AddPrerenderFromOmnibox(
         url, session_storage_namespace, size));
   }
diff --git a/chrome/browser/predictors/autocomplete_action_predictor.h b/chrome/browser/predictors/autocomplete_action_predictor.h
index 762d31a..b1c4f97 100644
--- a/chrome/browser/predictors/autocomplete_action_predictor.h
+++ b/chrome/browser/predictors/autocomplete_action_predictor.h
@@ -98,7 +98,7 @@
   // prerenders (if any).
   void StartPrerendering(
       const GURL& url,
-      content::SessionStorageNamespace* session_storage_namespace,
+      const content::SessionStorageNamespaceMap& session_storage_namespace_map,
       const gfx::Size& size);
 
   // Return true if the suggestion type warrants a TCP/IP preconnection.
diff --git a/chrome/browser/predictors/resource_prefetch_predictor.h b/chrome/browser/predictors/resource_prefetch_predictor.h
index 3776241..ed177e4 100644
--- a/chrome/browser/predictors/resource_prefetch_predictor.h
+++ b/chrome/browser/predictors/resource_prefetch_predictor.h
@@ -23,7 +23,7 @@
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
 #include "url/gurl.h"
-#include "webkit/glue/resource_type.h"
+#include "webkit/common/resource_type.h"
 
 class PredictorsHandler;
 class Profile;
diff --git a/chrome/browser/predictors/resource_prefetch_predictor_tables.h b/chrome/browser/predictors/resource_prefetch_predictor_tables.h
index f8a965e..6995388 100644
--- a/chrome/browser/predictors/resource_prefetch_predictor_tables.h
+++ b/chrome/browser/predictors/resource_prefetch_predictor_tables.h
@@ -14,7 +14,7 @@
 #include "chrome/browser/predictors/predictor_table_base.h"
 #include "chrome/browser/predictors/resource_prefetch_common.h"
 #include "url/gurl.h"
-#include "webkit/glue/resource_type.h"
+#include "webkit/common/resource_type.h"
 
 namespace sql {
 class Statement;
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index b606a80..14cc6a7 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -42,6 +42,7 @@
 #include "chrome/browser/net/http_server_properties_manager.h"
 #include "chrome/browser/net/net_pref_observer.h"
 #include "chrome/browser/net/predictor.h"
+#include "chrome/browser/net/pref_proxy_config_tracker_impl.h"
 #include "chrome/browser/net/ssl_config_service_manager.h"
 #include "chrome/browser/notifications/desktop_notification_service.h"
 #include "chrome/browser/notifications/notification_prefs_manager.h"
@@ -258,6 +259,7 @@
   chromeos::KioskAppManager::RegisterPrefs(registry);
   chromeos::LoginUtils::RegisterPrefs(registry);
   chromeos::Preferences::RegisterPrefs(registry);
+  chromeos::proxy_config::RegisterPrefs(registry);
   chromeos::RegisterDisplayLocalStatePrefs(registry);
   chromeos::ServicesCustomizationDocument::RegisterPrefs(registry);
   chromeos::system::AutomaticRebootManager::RegisterPrefs(registry);
diff --git a/chrome/browser/prefs/pref_service_browsertest.cc b/chrome/browser/prefs/pref_service_browsertest.cc
index fc1ba42..c3c0856 100644
--- a/chrome/browser/prefs/pref_service_browsertest.cc
+++ b/chrome/browser/prefs/pref_service_browsertest.cc
@@ -23,6 +23,10 @@
 #include "chrome/test/base/ui_test_utils.h"
 #include "ui/gfx/rect.h"
 
+#if defined(OS_WIN) && defined(USE_ASH)
+#include "base/win/windows_version.h"
+#endif
+
 // On GTK, resizing happens asynchronously and we currently don't have a way to
 // get called back (it's probably possible, but we don't have that code). Since
 // the GTK code is going away, not spending more time on this.
@@ -42,6 +46,12 @@
 #define MAYBE_Test Test
 #endif
 IN_PROC_BROWSER_TEST_F(PreservedWindowPlacement, MAYBE_Test) {
+#if defined(OS_WIN) && defined(USE_ASH)
+  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
+  if (base::win::GetVersion() >= base::win::VERSION_WIN8)
+    return;
+#endif
+
   gfx::Rect bounds = browser()->window()->GetBounds();
   gfx::Rect expected_bounds(gfx::Rect(20, 30, 400, 500));
   ASSERT_EQ(expected_bounds.ToString(), bounds.ToString());
@@ -112,6 +122,12 @@
 };
 
 IN_PROC_BROWSER_TEST_F(PreservedWindowPlacementIsLoaded, Test) {
+#if defined(OS_WIN) && defined(USE_ASH)
+  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
+  if (base::win::GetVersion() >= base::win::VERSION_WIN8)
+    return;
+#endif
+
   // The window should open with the new reference profile, with window
   // placement values stored in the user data directory.
   JSONFileValueSerializer deserializer(tmp_pref_file_);
@@ -165,6 +181,12 @@
 };
 
 IN_PROC_BROWSER_TEST_F(PreservedWindowPlacementIsMigrated, Test) {
+#if defined(OS_WIN) && defined(USE_ASH)
+  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
+  if (base::win::GetVersion() >= base::win::VERSION_WIN8)
+    return;
+#endif
+
   // The window should open with the old reference profile, with window
   // placement values stored in Local State.
 
diff --git a/chrome/browser/prerender/prerender_browsertest.cc b/chrome/browser/prerender/prerender_browsertest.cc
index cfaf608..41c3423 100644
--- a/chrome/browser/prerender/prerender_browsertest.cc
+++ b/chrome/browser/prerender/prerender_browsertest.cc
@@ -54,6 +54,7 @@
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/test_navigation_observer.h"
 #include "content/public/test/test_utils.h"
+#include "extensions/common/switches.h"
 #include "grit/generated_resources.h"
 #include "net/dns/mock_host_resolver.h"
 #include "net/url_request/url_request_context.h"
@@ -63,6 +64,10 @@
 #include "ui/base/l10n/l10n_util.h"
 #include "url/gurl.h"
 
+#if defined(OS_WIN) && defined(USE_ASH)
+#include "base/win/windows_version.h"
+#endif
+
 using content::BrowserThread;
 using content::DevToolsAgentHost;
 using content::DevToolsClientHost;
@@ -126,6 +131,7 @@
     case FINAL_STATUS_RENDERER_CRASHED:
     case FINAL_STATUS_CANCELLED:
     case FINAL_STATUS_DEVTOOLS_ATTACHED:
+    case FINAL_STATUS_PAGE_BEING_CAPTURED:
       return true;
     default:
       return false;
@@ -639,7 +645,7 @@
         current_browser()->tab_strip_model()->GetActiveWebContents();
     if (!web_contents)
       return NULL;
-    return web_contents->GetController().GetSessionStorageNamespace();
+    return web_contents->GetController().GetDefaultSessionStorageNamespace();
   }
 
   virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
@@ -1158,10 +1164,6 @@
         current_browser(), dest_url, disposition,
         ui_test_utils::BROWSER_TEST_NONE);
 
-    // Make sure the PrerenderContents found earlier was used or removed,
-    // unless we expect the swap in to fail.
-    EXPECT_EQ(expect_swap_to_succeed, !GetPrerenderContents());
-
     if (call_javascript_ && web_contents && expect_swap_to_succeed) {
       if (page_load_observer.get())
         page_load_observer->Wait();
@@ -2697,6 +2699,12 @@
 // Check that NaCl plugins work when enabled, with prerendering.
 IN_PROC_BROWSER_TEST_F(PrerenderBrowserTestWithNaCl,
                        PrerenderNaClPluginEnabled) {
+#if defined(OS_WIN) && defined(USE_ASH)
+  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
+  if (base::win::GetVersion() >= base::win::VERSION_WIN8)
+    return;
+#endif
+
   PrerenderTestURL("files/prerender/prerender_plugin_nacl_enabled.html",
                    FINAL_STATUS_USED,
                    1);
@@ -2764,7 +2772,7 @@
   extensions::FrameNavigationState::set_allow_extension_scheme(true);
 
   CommandLine::ForCurrentProcess()->AppendSwitch(
-      switches::kAllowLegacyExtensionManifests);
+      extensions::switches::kAllowLegacyExtensionManifests);
 
   // Wait for the extension to set itself up and return control to us.
   ASSERT_TRUE(
@@ -2899,4 +2907,23 @@
   NavigateToDestUrlAndWaitForPassTitle();
 }
 
+// Checks that a prerender that creates an audio stream (via a WebAudioDevice)
+// is cancelled.
+// http://crbug.com/261489
+IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, DISABLED_PrerenderWebAudioDevice) {
+  PrerenderTestURL("files/prerender/prerender_web_audio_device.html",
+                   FINAL_STATUS_CREATING_AUDIO_STREAM, 1);
+}
+
+// Checks that prerenders do not swap in to WebContents being captured.
+IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, PrerenderCapturedWebContents) {
+  PrerenderTestURL("files/prerender/prerender_page.html",
+                   FINAL_STATUS_PAGE_BEING_CAPTURED, 1);
+  WebContents* web_contents =
+      current_browser()->tab_strip_model()->GetActiveWebContents();
+  web_contents->IncrementCapturerCount();
+  NavigateToDestURLWithDisposition(CURRENT_TAB, false);
+  web_contents->DecrementCapturerCount();
+}
+
 }  // namespace prerender
diff --git a/chrome/browser/prerender/prerender_contents.cc b/chrome/browser/prerender/prerender_contents.cc
index 6f7caf4..957809f 100644
--- a/chrome/browser/prerender/prerender_contents.cc
+++ b/chrome/browser/prerender/prerender_contents.cc
@@ -180,8 +180,9 @@
 
   SessionStorageNamespace* session_storage_namespace = NULL;
   if (prerender_contents_) {
+    // TODO(ajwong): This does not correctly handle storage for isolated apps.
     session_storage_namespace = prerender_contents_->
-        GetController().GetSessionStorageNamespace();
+        GetController().GetDefaultSessionStorageNamespace();
   }
   prerender_manager_->StartPendingPrerenders(
       child_id_, &pending_prerenders_, session_storage_namespace);
@@ -473,8 +474,12 @@
 
 WebContents* PrerenderContents::CreateWebContents(
     SessionStorageNamespace* session_storage_namespace) {
+  // TODO(ajwong): Remove the temporary map once prerendering is aware of
+  // multiple session storage namespaces per tab.
+  content::SessionStorageNamespaceMap session_storage_namespace_map;
+  session_storage_namespace_map[std::string()] = session_storage_namespace;
   return WebContents::CreateWithSessionStorage(
-      WebContents::CreateParams(profile_), session_storage_namespace);
+      WebContents::CreateParams(profile_), session_storage_namespace_map);
 }
 
 void PrerenderContents::NotifyPrerenderStart() {
diff --git a/chrome/browser/prerender/prerender_final_status.cc b/chrome/browser/prerender/prerender_final_status.cc
index f3f2cfe..6455dcf 100644
--- a/chrome/browser/prerender/prerender_final_status.cc
+++ b/chrome/browser/prerender/prerender_final_status.cc
@@ -54,12 +54,14 @@
   "OpenURL",
   "WouldHaveBeenUsed",
   "Register Protocol Handler",
+  "Creating Audio Stream",
+  "Page Being Captured",
   "Max",
 };
 COMPILE_ASSERT(arraysize(kFinalStatusNames) == FINAL_STATUS_MAX + 1,
                PrerenderFinalStatus_name_count_mismatch);
 
-}
+}  // namespace
 
 const char* NameFromFinalStatus(FinalStatus final_status) {
   DCHECK_LT(static_cast<unsigned int>(final_status),
diff --git a/chrome/browser/prerender/prerender_final_status.h b/chrome/browser/prerender/prerender_final_status.h
index 87922f8..8e989c6 100644
--- a/chrome/browser/prerender/prerender_final_status.h
+++ b/chrome/browser/prerender/prerender_final_status.h
@@ -55,6 +55,8 @@
   FINAL_STATUS_OPEN_URL = 40,
   FINAL_STATUS_WOULD_HAVE_BEEN_USED = 41,
   FINAL_STATUS_REGISTER_PROTOCOL_HANDLER = 42,
+  FINAL_STATUS_CREATING_AUDIO_STREAM = 43,
+  FINAL_STATUS_PAGE_BEING_CAPTURED = 44,
   FINAL_STATUS_MAX,
 };
 
diff --git a/chrome/browser/prerender/prerender_local_predictor.cc b/chrome/browser/prerender/prerender_local_predictor.cc
index 398a06f..93525f6 100644
--- a/chrome/browser/prerender/prerender_local_predictor.cc
+++ b/chrome/browser/prerender/prerender_local_predictor.cc
@@ -536,7 +536,7 @@
 
 
   scoped_refptr<SessionStorageNamespace> session_storage_namespace =
-      source_web_contents->GetController().GetSessionStorageNamespace();
+      source_web_contents->GetController().GetDefaultSessionStorageNamespace();
 
   gfx::Rect container_bounds;
   source_web_contents->GetView()->GetContainerBounds(&container_bounds);
@@ -883,7 +883,7 @@
           p->prerender_handle->Matches(
               url,
               web_contents->GetController().
-              GetSessionStorageNamespace());
+              GetDefaultSessionStorageNamespace());
     }
   }
   if (best_matched_prerender) {
diff --git a/chrome/browser/prerender/prerender_manager.cc b/chrome/browser/prerender/prerender_manager.cc
index e93ccc9..b955695 100644
--- a/chrome/browser/prerender/prerender_manager.cc
+++ b/chrome/browser/prerender/prerender_manager.cc
@@ -39,6 +39,7 @@
 #include "chrome/browser/prerender/prerender_tracker.h"
 #include "chrome/browser/prerender/prerender_util.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/tab_contents/tab_util.h"
 #include "chrome/browser/ui/tab_contents/core_tab_helper.h"
 #include "chrome/browser/ui/tab_contents/core_tab_helper_delegate.h"
 #include "chrome/common/chrome_switches.h"
@@ -111,7 +112,8 @@
       final_status != FINAL_STATUS_CACHE_OR_HISTORY_CLEARED &&
       final_status != FINAL_STATUS_CANCELLED &&
       final_status != FINAL_STATUS_DEVTOOLS_ATTACHED &&
-      final_status != FINAL_STATUS_CROSS_SITE_NAVIGATION_PENDING;
+      final_status != FINAL_STATUS_CROSS_SITE_NAVIGATION_PENDING &&
+      final_status != FINAL_STATUS_PAGE_BEING_CAPTURED;
 }
 
 void CheckIfCookiesExistForDomainResultOnUIThread(
@@ -275,9 +277,13 @@
   notification_registrar_.Add(
       this, chrome::NOTIFICATION_COOKIE_CHANGED,
       content::NotificationService::AllBrowserContextsAndSources());
+
+  MediaCaptureDevicesDispatcher::GetInstance()->AddObserver(this);
 }
 
 PrerenderManager::~PrerenderManager() {
+  MediaCaptureDevicesDispatcher::GetInstance()->RemoveObserver(this);
+
   // The earlier call to BrowserContextKeyedService::Shutdown() should have
   // emptied these vectors already.
   DCHECK(active_prerenders_.empty());
@@ -323,8 +329,10 @@
       return NULL;
     if (source_web_contents->GetURL().host() == url.host())
       origin = ORIGIN_LINK_REL_PRERENDER_SAMEDOMAIN;
+    // TODO(ajwong): This does not correctly handle storage for isolated apps.
     session_storage_namespace =
-        source_web_contents->GetController().GetSessionStorageNamespace();
+        source_web_contents->GetController()
+            .GetDefaultSessionStorageNamespace();
   }
 
   // If the prerender request comes from a recently cancelled prerender that
@@ -406,8 +414,10 @@
 
   DeleteOldEntries();
   to_delete_prerenders_.clear();
+  // TODO(ajwong): This doesn't handle isolated apps correctly.
   PrerenderData* prerender_data = FindPrerenderData(
-      url, web_contents->GetController().GetSessionStorageNamespace());
+          url,
+          web_contents->GetController().GetDefaultSessionStorageNamespace());
   if (!prerender_data)
     return false;
   DCHECK(prerender_data->contents());
@@ -434,6 +444,12 @@
     return false;
   }
 
+  // Do not swap in the prerender if the current WebContents is being captured.
+  if (web_contents->GetCapturerCount() > 0) {
+    prerender_data->contents()->Destroy(FINAL_STATUS_PAGE_BEING_CAPTURED);
+    return false;
+  }
+
   // If we are just in the control group (which can be detected by noticing
   // that prerendering hasn't even started yet), record that |web_contents| now
   // would be showing a prerendered contents, but otherwise, don't do anything.
@@ -1432,6 +1448,21 @@
   CookieChanged(content::Details<ChromeCookieDetails>(details).ptr());
 }
 
+void PrerenderManager::OnCreatingAudioStream(int render_process_id,
+                                             int render_view_id) {
+  WebContents* tab = tab_util::GetWebContentsByID(
+      render_process_id, render_view_id);
+  if (!tab)
+    return;
+
+  if (!IsWebContentsPrerendering(tab, NULL))
+    return;
+
+  prerender_tracker()->TryCancel(
+      render_process_id, render_view_id,
+      prerender::FINAL_STATUS_CREATING_AUDIO_STREAM);
+}
+
 void PrerenderManager::RecordLikelyLoginOnURL(const GURL& url) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   if (!IsWebURL(url))
diff --git a/chrome/browser/prerender/prerender_manager.h b/chrome/browser/prerender/prerender_manager.h
index 67ff3f3..8789699 100644
--- a/chrome/browser/prerender/prerender_manager.h
+++ b/chrome/browser/prerender/prerender_manager.h
@@ -19,6 +19,7 @@
 #include "base/threading/non_thread_safe.h"
 #include "base/time/time.h"
 #include "base/timer/timer.h"
+#include "chrome/browser/media/media_capture_devices_dispatcher.h"
 #include "chrome/browser/predictors/logged_in_predictor_table.h"
 #include "chrome/browser/prerender/prerender_config.h"
 #include "chrome/browser/prerender/prerender_contents.h"
@@ -78,7 +79,8 @@
 class PrerenderManager : public base::SupportsWeakPtr<PrerenderManager>,
                          public base::NonThreadSafe,
                          public content::NotificationObserver,
-                         public BrowserContextKeyedService {
+                         public BrowserContextKeyedService,
+                         public MediaCaptureDevicesDispatcher::Observer {
  public:
   // NOTE: New values need to be appended, since they are used in histograms.
   enum PrerenderManagerMode {
@@ -274,6 +276,10 @@
                        const content::NotificationSource& source,
                        const content::NotificationDetails& details) OVERRIDE;
 
+  // MediaCaptureDevicesDispatcher::Observer
+  virtual void OnCreatingAudioStream(int render_process_id,
+                                     int render_view_id) OVERRIDE;
+
   const Config& config() const { return config_; }
   Config& mutable_config() { return config_; }
 
diff --git a/chrome/browser/printing/background_printing_manager.cc b/chrome/browser/printing/background_printing_manager.cc
index 4db8f15..f0aa96a 100644
--- a/chrome/browser/printing/background_printing_manager.cc
+++ b/chrome/browser/printing/background_printing_manager.cc
@@ -63,16 +63,15 @@
                    rph_source);
   }
 
-  // Activate the initiator tab.
+  // Activate the initiator.
   PrintPreviewDialogController* dialog_controller =
       PrintPreviewDialogController::GetInstance();
   if (!dialog_controller)
     return;
-  WebContents* initiator_tab =
-      dialog_controller->GetInitiatorTab(preview_dialog);
-  if (!initiator_tab)
+  WebContents* initiator = dialog_controller->GetInitiator(preview_dialog);
+  if (!initiator)
     return;
-  initiator_tab->GetDelegate()->ActivateContents(initiator_tab);
+  initiator->GetDelegate()->ActivateContents(initiator);
 }
 
 void BackgroundPrintingManager::Observe(
diff --git a/chrome/browser/printing/cloud_print/test/cloud_print_policy_browsertest.cc b/chrome/browser/printing/cloud_print/test/cloud_print_policy_browsertest.cc
index 6433df6..eb238e5 100644
--- a/chrome/browser/printing/cloud_print/test/cloud_print_policy_browsertest.cc
+++ b/chrome/browser/printing/cloud_print/test/cloud_print_policy_browsertest.cc
@@ -14,6 +14,10 @@
 #include "content/public/browser/notification_service.h"
 #include "content/public/common/result_codes.h"
 
+#if defined(OS_WIN) && defined(USE_ASH)
+#include "base/win/windows_version.h"
+#endif
+
 // These tests don't apply to the Mac version; see GetCommandLineForRelaunch
 // for details.
 #if defined(OS_MACOSX)
@@ -28,6 +32,12 @@
 };
 
 IN_PROC_BROWSER_TEST_F(CloudPrintPolicyTest, NormalPassedFlag) {
+#if defined(OS_WIN) && defined(USE_ASH)
+  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
+  if (base::win::GetVersion() >= base::win::VERSION_WIN8)
+    return;
+#endif
+
   base::FilePath test_file_path = ui_test_utils::GetTestFilePath(
       base::FilePath(), base::FilePath().AppendASCII("empty.html"));
   CommandLine new_command_line(GetCommandLineForRelaunch());
diff --git a/chrome/browser/printing/print_preview_dialog_controller.cc b/chrome/browser/printing/print_preview_dialog_controller.cc
index 5088ffb..6d96eb3 100644
--- a/chrome/browser/printing/print_preview_dialog_controller.cc
+++ b/chrome/browser/printing/print_preview_dialog_controller.cc
@@ -40,9 +40,9 @@
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_delegate.h"
 #include "content/public/browser/web_contents_view.h"
+#include "content/public/common/webplugininfo.h"
 #include "ui/web_dialogs/web_dialog_delegate.h"
 #include "ui/web_dialogs/web_dialog_web_contents_delegate.h"
-#include "webkit/plugins/webplugininfo.h"
 
 using content::NativeWebKeyboardEvent;
 using content::NavigationController;
@@ -59,7 +59,7 @@
   if (!PathService::Get(chrome::FILE_PDF_PLUGIN, &pdf_plugin_path))
     return;
 
-  webkit::WebPluginInfo pdf_plugin;
+  content::WebPluginInfo pdf_plugin;
   if (!content::PluginService::GetInstance()->GetPluginInfoByPath(
       pdf_plugin_path, &pdf_plugin))
     return;
@@ -74,7 +74,7 @@
 // will look like.
 class PrintPreviewDialogDelegate : public WebDialogDelegate {
  public:
-  explicit PrintPreviewDialogDelegate(WebContents* initiator_tab);
+  explicit PrintPreviewDialogDelegate(WebContents* initiator);
   virtual ~PrintPreviewDialogDelegate();
 
   virtual ui::ModalType GetDialogModalType() const OVERRIDE;
@@ -90,14 +90,13 @@
   virtual bool ShouldShowDialogTitle() const OVERRIDE;
 
  private:
-  WebContents* initiator_tab_;
+  WebContents* initiator_;
 
   DISALLOW_COPY_AND_ASSIGN(PrintPreviewDialogDelegate);
 };
 
-PrintPreviewDialogDelegate::PrintPreviewDialogDelegate(
-    WebContents* initiator_tab) {
-  initiator_tab_ = initiator_tab;
+PrintPreviewDialogDelegate::PrintPreviewDialogDelegate(WebContents* initiator)
+    : initiator_(initiator) {
 }
 
 PrintPreviewDialogDelegate::~PrintPreviewDialogDelegate() {
@@ -129,7 +128,7 @@
   const int kBorder = 25;
   const int kConstrainedWindowOverlap = 3;
   gfx::Rect rect;
-  initiator_tab_->GetView()->GetContainerBounds(&rect);
+  initiator_->GetView()->GetContainerBounds(&rect);
   size->set_width(std::max(rect.width(), kMinDialogSize.width()) - 2 * kBorder);
   size->set_height(std::max(rect.height(), kMinDialogSize.height()) - kBorder +
                    kConstrainedWindowOverlap);
@@ -165,7 +164,7 @@
 // renderer to the browser.
 class PrintPreviewWebContentDelegate : public WebDialogWebContentsDelegate {
  public:
-  PrintPreviewWebContentDelegate(Profile* profile, WebContents* initiator_tab);
+  PrintPreviewWebContentDelegate(Profile* profile, WebContents* initiator);
   virtual ~PrintPreviewWebContentDelegate();
 
   // Overridden from WebDialogWebContentsDelegate:
@@ -181,9 +180,9 @@
 
 PrintPreviewWebContentDelegate::PrintPreviewWebContentDelegate(
     Profile* profile,
-    WebContents* initiator_tab)
+    WebContents* initiator)
     : WebDialogWebContentsDelegate(profile, new ChromeWebContentsHandler),
-      tab_(initiator_tab) {}
+      tab_(initiator) {}
 
 PrintPreviewWebContentDelegate::~PrintPreviewWebContentDelegate() {}
 
@@ -216,28 +215,28 @@
 }
 
 // static
-void PrintPreviewDialogController::PrintPreview(WebContents* initiator_tab) {
-  if (initiator_tab->ShowingInterstitialPage())
+void PrintPreviewDialogController::PrintPreview(WebContents* initiator) {
+  if (initiator->ShowingInterstitialPage())
     return;
 
   PrintPreviewDialogController* dialog_controller = GetInstance();
   if (!dialog_controller)
     return;
-  if (!dialog_controller->GetOrCreatePreviewDialog(initiator_tab))
-    PrintViewManager::FromWebContents(initiator_tab)->PrintPreviewDone();
+  if (!dialog_controller->GetOrCreatePreviewDialog(initiator))
+    PrintViewManager::FromWebContents(initiator)->PrintPreviewDone();
 }
 
 WebContents* PrintPreviewDialogController::GetOrCreatePreviewDialog(
-    WebContents* initiator_tab) {
-  DCHECK(initiator_tab);
+    WebContents* initiator) {
+  DCHECK(initiator);
 
-  // Get the print preview dialog for |initiator_tab|.
-  WebContents* preview_dialog = GetPrintPreviewForContents(initiator_tab);
+  // Get the print preview dialog for |initiator|.
+  WebContents* preview_dialog = GetPrintPreviewForContents(initiator);
   if (!preview_dialog)
-    return CreatePrintPreviewDialog(initiator_tab);
+    return CreatePrintPreviewDialog(initiator);
 
-  // Show the initiator tab holding the existing preview dialog.
-  initiator_tab->GetDelegate()->ActivateContents(initiator_tab);
+  // Show the initiator holding the existing preview dialog.
+  initiator->GetDelegate()->ActivateContents(initiator);
   return preview_dialog;
 }
 
@@ -252,7 +251,7 @@
   for (it = preview_dialog_map_.begin();
        it != preview_dialog_map_.end();
        ++it) {
-    // If |contents| is an initiator tab.
+    // If |contents| is an initiator.
     if (contents == it->second) {
       // Return the associated preview dialog.
       return it->first;
@@ -261,7 +260,7 @@
   return NULL;
 }
 
-WebContents* PrintPreviewDialogController::GetInitiatorTab(
+WebContents* PrintPreviewDialogController::GetInitiator(
     WebContents* preview_dialog) {
   PrintPreviewDialogMap::iterator it = preview_dialog_map_.find(preview_dialog);
   return (it != preview_dialog_map_.end()) ? it->second : NULL;
@@ -297,13 +296,13 @@
           url.host() == chrome::kChromeUIPrintHost);
 }
 
-void PrintPreviewDialogController::EraseInitiatorTabInfo(
+void PrintPreviewDialogController::EraseInitiatorInfo(
     WebContents* preview_dialog) {
   PrintPreviewDialogMap::iterator it = preview_dialog_map_.find(preview_dialog);
   if (it == preview_dialog_map_.end())
     return;
 
-  RemoveObservers(it->second);
+  RemoveObservers(it->second, INITIATOR);
   preview_dialog_map_[preview_dialog] = NULL;
 }
 
@@ -313,17 +312,17 @@
     content::RenderProcessHost* rph) {
   // Store contents in a vector and deal with them after iterating through
   // |preview_dialog_map_| because RemoveFoo() can change |preview_dialog_map_|.
-  std::vector<WebContents*> closed_initiator_tabs;
+  std::vector<WebContents*> closed_initiators;
   std::vector<WebContents*> closed_preview_dialogs;
   for (PrintPreviewDialogMap::iterator iter = preview_dialog_map_.begin();
        iter != preview_dialog_map_.end(); ++iter) {
     WebContents* preview_dialog = iter->first;
-    WebContents* initiator_tab = iter->second;
+    WebContents* initiator = iter->second;
     if (preview_dialog->GetRenderProcessHost() == rph) {
       closed_preview_dialogs.push_back(preview_dialog);
-    } else if (initiator_tab &&
-               initiator_tab->GetRenderProcessHost() == rph) {
-      closed_initiator_tabs.push_back(initiator_tab);
+    } else if (initiator &&
+               initiator->GetRenderProcessHost() == rph) {
+      closed_initiators.push_back(initiator);
     }
   }
 
@@ -335,8 +334,8 @@
       print_preview_ui->OnPrintPreviewDialogClosed();
   }
 
-  for (size_t i = 0; i < closed_initiator_tabs.size(); ++i)
-    RemoveInitiatorTab(closed_initiator_tabs[i]);
+  for (size_t i = 0; i < closed_initiators.size(); ++i)
+    RemoveInitiator(closed_initiators[i]);
 }
 
 void PrintPreviewDialogController::OnWebContentsDestroyed(
@@ -350,7 +349,7 @@
   if (contents == preview_dialog)
     RemovePreviewDialog(contents);
   else
-    RemoveInitiatorTab(contents);
+    RemoveInitiator(contents);
 }
 
 void PrintPreviewDialogController::OnNavEntryCommitted(
@@ -361,42 +360,40 @@
     return;
   }
 
-  if (contents == preview_dialog) {
-    // Preview dialog navigated.
-    if (details) {
-      content::PageTransition transition_type =
-          details->entry->GetTransitionType();
-      content::NavigationType nav_type = details->type;
+  DCHECK_EQ(contents, preview_dialog);
 
-      // New |preview_dialog| is created. Don't update/erase map entry.
-      if (waiting_for_new_preview_page_ &&
-          transition_type == content::PAGE_TRANSITION_AUTO_TOPLEVEL &&
-          nav_type == content::NAVIGATION_TYPE_NEW_PAGE) {
-        waiting_for_new_preview_page_ = false;
-        SaveInitiatorTabTitle(preview_dialog);
-        return;
-      }
+  // Preview dialog navigated.
+  if (details) {
+    content::PageTransition transition_type =
+        details->entry->GetTransitionType();
+    content::NavigationType nav_type = details->type;
 
-      // Cloud print sign-in causes a reload.
-      if (!waiting_for_new_preview_page_ &&
-          transition_type == content::PAGE_TRANSITION_RELOAD &&
-          nav_type == content::NAVIGATION_TYPE_EXISTING_PAGE &&
-          IsPrintPreviewURL(details->previous_url)) {
-        return;
-      }
+    // New |preview_dialog| is created. Don't update/erase map entry.
+    if (waiting_for_new_preview_page_ &&
+        transition_type == content::PAGE_TRANSITION_AUTO_TOPLEVEL &&
+        nav_type == content::NAVIGATION_TYPE_NEW_PAGE) {
+      waiting_for_new_preview_page_ = false;
+      SaveInitiatorTitle(preview_dialog);
+      return;
     }
-    NOTREACHED();
-    return;
+
+    // Cloud print sign-in causes a reload.
+    if (!waiting_for_new_preview_page_ &&
+        transition_type == content::PAGE_TRANSITION_RELOAD &&
+        nav_type == content::NAVIGATION_TYPE_EXISTING_PAGE &&
+        IsPrintPreviewURL(details->previous_url)) {
+      return;
+    }
   }
 
-  RemoveInitiatorTab(contents);
+  NOTREACHED();
 }
 
 WebContents* PrintPreviewDialogController::CreatePrintPreviewDialog(
-    WebContents* initiator_tab) {
+    WebContents* initiator) {
   base::AutoReset<bool> auto_reset(&is_creating_print_preview_dialog_, true);
   Profile* profile =
-      Profile::FromBrowserContext(initiator_tab->GetBrowserContext());
+      Profile::FromBrowserContext(initiator->GetBrowserContext());
   if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kChromeFrame)) {
     // Chrome Frame only ever runs on the native desktop, so it is safe to
     // create the popup on the native desktop.
@@ -412,45 +409,48 @@
   // |web_dialog_ui_delegate| deletes itself in
   // PrintPreviewDialogDelegate::OnDialogClosed().
   WebDialogDelegate* web_dialog_delegate =
-      new PrintPreviewDialogDelegate(initiator_tab);
+      new PrintPreviewDialogDelegate(initiator);
   // |web_dialog_delegate|'s owner is |constrained_delegate|.
   PrintPreviewWebContentDelegate* pp_wcd =
-      new PrintPreviewWebContentDelegate(profile, initiator_tab);
+      new PrintPreviewWebContentDelegate(profile, initiator);
   ConstrainedWebDialogDelegate* constrained_delegate =
       CreateConstrainedWebDialog(profile,
                                  web_dialog_delegate,
                                  pp_wcd,
-                                 initiator_tab);
+                                 initiator);
   WebContents* preview_dialog = constrained_delegate->GetWebContents();
   EnableInternalPDFPluginForContents(preview_dialog);
   PrintViewManager::CreateForWebContents(preview_dialog);
 
   // Add an entry to the map.
-  preview_dialog_map_[preview_dialog] = initiator_tab;
+  preview_dialog_map_[preview_dialog] = initiator;
   waiting_for_new_preview_page_ = true;
 
-  AddObservers(initiator_tab);
-  AddObservers(preview_dialog);
+  AddObservers(initiator, INITIATOR);
+  AddObservers(preview_dialog, PREVIEW_DIALOG);
 
   return preview_dialog;
 }
 
-void PrintPreviewDialogController::SaveInitiatorTabTitle(
+void PrintPreviewDialogController::SaveInitiatorTitle(
     WebContents* preview_dialog) {
-  WebContents* initiator_tab = GetInitiatorTab(preview_dialog);
-  if (initiator_tab && preview_dialog->GetWebUI()) {
+  WebContents* initiator = GetInitiator(preview_dialog);
+  if (initiator && preview_dialog->GetWebUI()) {
     PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(
         preview_dialog->GetWebUI()->GetController());
-    print_preview_ui->SetInitiatorTabTitle(
-        PrintViewManager::FromWebContents(initiator_tab)->RenderSourceName());
+    print_preview_ui->SetInitiatorTitle(
+        PrintViewManager::FromWebContents(initiator)->RenderSourceName());
   }
 }
 
-void PrintPreviewDialogController::AddObservers(WebContents* contents) {
+void PrintPreviewDialogController::AddObservers(WebContents* contents,
+                                                ContentsType contents_type) {
   registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
                  content::Source<WebContents>(contents));
-  registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED,
-      content::Source<NavigationController>(&contents->GetController()));
+  if (contents_type == PREVIEW_DIALOG) {
+    registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED,
+        content::Source<NavigationController>(&contents->GetController()));
+  }
 
   // Multiple sites may share the same RenderProcessHost, so check if this
   // notification has already been added.
@@ -463,11 +463,14 @@
   }
 }
 
-void PrintPreviewDialogController::RemoveObservers(WebContents* contents) {
+void PrintPreviewDialogController::RemoveObservers(WebContents* contents,
+                                                   ContentsType contents_type) {
   registrar_.Remove(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
                     content::Source<WebContents>(contents));
-  registrar_.Remove(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED,
-      content::Source<NavigationController>(&contents->GetController()));
+  if (contents_type == PREVIEW_DIALOG) {
+    registrar_.Remove(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED,
+        content::Source<NavigationController>(&contents->GetController()));
+  }
 
   // Multiple sites may share the same RenderProcessHost, so check if this
   // notification has already been added.
@@ -480,43 +483,43 @@
   }
 }
 
-void PrintPreviewDialogController::RemoveInitiatorTab(
-    WebContents* initiator_tab) {
-  WebContents* preview_dialog = GetPrintPreviewForContents(initiator_tab);
+void PrintPreviewDialogController::RemoveInitiator(
+    WebContents* initiator) {
+  WebContents* preview_dialog = GetPrintPreviewForContents(initiator);
   DCHECK(preview_dialog);
   // Update the map entry first, so when the print preview dialog gets destroyed
   // and reaches RemovePreviewDialog(), it does not attempt to also remove the
-  // initiator tab's observers.
+  // initiator's observers.
   preview_dialog_map_[preview_dialog] = NULL;
-  RemoveObservers(initiator_tab);
+  RemoveObservers(initiator, INITIATOR);
 
-  PrintViewManager::FromWebContents(initiator_tab)->PrintPreviewDone();
+  PrintViewManager::FromWebContents(initiator)->PrintPreviewDone();
 
-  // Initiator tab is closed. Close the print preview dialog too.
+  // initiator is closed. Close the print preview dialog too.
   PrintPreviewUI* print_preview_ui =
       static_cast<PrintPreviewUI*>(preview_dialog->GetWebUI()->GetController());
   if (print_preview_ui)
-    print_preview_ui->OnInitiatorTabClosed();
+    print_preview_ui->OnInitiatorClosed();
 }
 
 void PrintPreviewDialogController::RemovePreviewDialog(
     WebContents* preview_dialog) {
-  // Remove the initiator tab's observers before erasing the mapping.
-  WebContents* initiator_tab = GetInitiatorTab(preview_dialog);
-  if (initiator_tab) {
-    RemoveObservers(initiator_tab);
-    PrintViewManager::FromWebContents(initiator_tab)->PrintPreviewDone();
+  // Remove the initiator's observers before erasing the mapping.
+  WebContents* initiator = GetInitiator(preview_dialog);
+  if (initiator) {
+    RemoveObservers(initiator, INITIATOR);
+    PrintViewManager::FromWebContents(initiator)->PrintPreviewDone();
   }
 
   // Print preview WebContents is destroyed. Notify |PrintPreviewUI| to abort
-  // the initiator tab preview request.
+  // the initiator preview request.
   PrintPreviewUI* print_preview_ui =
       static_cast<PrintPreviewUI*>(preview_dialog->GetWebUI()->GetController());
   if (print_preview_ui)
     print_preview_ui->OnPrintPreviewDialogDestroyed();
 
   preview_dialog_map_.erase(preview_dialog);
-  RemoveObservers(preview_dialog);
+  RemoveObservers(preview_dialog, PREVIEW_DIALOG);
 }
 
 }  // namespace printing
diff --git a/chrome/browser/printing/print_preview_dialog_controller.h b/chrome/browser/printing/print_preview_dialog_controller.h
index 0ce70db..da5d385 100644
--- a/chrome/browser/printing/print_preview_dialog_controller.h
+++ b/chrome/browser/printing/print_preview_dialog_controller.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+ // 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.
 
@@ -22,9 +22,9 @@
 
 namespace printing {
 
-// For print preview, the tab that initiates the printing operation is the
-// initiator tab, and the constrained dialog that shows the print preview is
-// the print preview dialog.
+// For print preview, the WebContents that initiates the printing operation is
+// the initiator, and the constrained dialog that shows the print preview is the
+// print preview dialog.
 // This class manages print preview dialog creation and destruction, and keeps
 // track of the 1:1 relationship between initiatora tabs and print preview
 // dialogs.
@@ -36,14 +36,14 @@
 
   static PrintPreviewDialogController* GetInstance();
 
-  // Initiate print preview for |initiator_tab|.
+  // Initiate print preview for |initiator|.
   // Call this instead of GetOrCreatePreviewDialog().
-  static void PrintPreview(content::WebContents* initiator_tab);
+  static void PrintPreview(content::WebContents* initiator);
 
-  // Get/Create the print preview dialog for |initiator_tab|.
+  // Get/Create the print preview dialog for |initiator|.
   // Exposed for unit tests.
   content::WebContents* GetOrCreatePreviewDialog(
-      content::WebContents* initiator_tab);
+      content::WebContents* initiator);
 
   // Returns the preview dialog for |contents|.
   // Returns |contents| if |contents| is a preview dialog.
@@ -51,9 +51,9 @@
   content::WebContents* GetPrintPreviewForContents(
       content::WebContents* contents) const;
 
-  // Returns the initiator tab for |preview_dialog|.
-  // Returns NULL if no initiator tab exists for |preview_dialog|.
-  content::WebContents* GetInitiatorTab(content::WebContents* preview_dialog);
+  // Returns the initiator for |preview_dialog|.
+  // Returns NULL if no initiator exists for |preview_dialog|.
+  content::WebContents* GetInitiator(content::WebContents* preview_dialog);
 
   // content::NotificationObserver implementation.
   virtual void Observe(int type,
@@ -66,8 +66,8 @@
   // Returns true if |url| is a print preview url.
   static bool IsPrintPreviewURL(const GURL& url);
 
-  // Erase the initiator tab info associated with |preview_tab|.
-  void EraseInitiatorTabInfo(content::WebContents* preview_tab);
+  // Erase the initiator info associated with |preview_dialog|.
+  void EraseInitiatorInfo(content::WebContents* preview_dialog);
 
   bool is_creating_print_preview_dialog() const {
     return is_creating_print_preview_dialog_;
@@ -76,9 +76,16 @@
  private:
   friend class base::RefCounted<PrintPreviewDialogController>;
 
-  // 1:1 relationship between a print preview dialog and its initiator tab.
+  // Used to distinguish between the two varieties of WebContents dealt with by
+  // this class.
+  enum ContentsType {
+    INITIATOR,
+    PREVIEW_DIALOG
+  };
+
+  // 1:1 relationship between a print preview dialog and its initiator.
   // Key: Print preview dialog.
-  // Value: Initiator tab.
+  // Value: Initiator.
   typedef std::map<content::WebContents*, content::WebContents*>
       PrintPreviewDialogMap;
 
@@ -99,21 +106,22 @@
 
   // Creates a new print preview dialog.
   content::WebContents* CreatePrintPreviewDialog(
-      content::WebContents* initiator_tab);
+      content::WebContents* initiator);
 
-  // Helper function to store the title of the initiator tab associated with
+  // Helper function to store the title of the initiator associated with
   // |preview_dialog| in |preview_dialog|'s PrintPreviewUI.
-  void SaveInitiatorTabTitle(content::WebContents* preview_dialog);
+  void SaveInitiatorTitle(content::WebContents* preview_dialog);
 
   // Adds/Removes observers for notifications from |contents|.
-  void AddObservers(content::WebContents* contents);
-  void RemoveObservers(content::WebContents* contents);
+  void AddObservers(content::WebContents* contents, ContentsType contents_type);
+  void RemoveObservers(content::WebContents* contents,
+                       ContentsType contents_type);
 
   // Removes WebContents when they close/crash/navigate.
-  void RemoveInitiatorTab(content::WebContents* initiator_tab);
+  void RemoveInitiator(content::WebContents* initiator);
   void RemovePreviewDialog(content::WebContents* preview_dialog);
 
-  // Mapping between print preview dialog and the corresponding initiator tab.
+  // Mapping between print preview dialog and the corresponding initiator.
   PrintPreviewDialogMap preview_dialog_map_;
 
   // A registrar for listening notifications.
diff --git a/chrome/browser/printing/print_preview_dialog_controller_browsertest.cc b/chrome/browser/printing/print_preview_dialog_controller_browsertest.cc
index b9bcb4e..c64c3bf 100644
--- a/chrome/browser/printing/print_preview_dialog_controller_browsertest.cc
+++ b/chrome/browser/printing/print_preview_dialog_controller_browsertest.cc
@@ -103,11 +103,11 @@
 
 class PrintPreviewDialogControllerBrowserTest : public InProcessBrowserTest {
  public:
-  PrintPreviewDialogControllerBrowserTest() : initiator_tab_(NULL) {}
+  PrintPreviewDialogControllerBrowserTest() : initiator_(NULL) {}
   virtual ~PrintPreviewDialogControllerBrowserTest() {}
 
-  WebContents* initiator_tab() {
-    return initiator_tab_;
+  WebContents* initiator() {
+    return initiator_;
   }
 
   void PrintPreview() {
@@ -120,7 +120,7 @@
   WebContents* GetPrintPreviewDialog() {
     printing::PrintPreviewDialogController* dialog_controller =
         printing::PrintPreviewDialogController::GetInstance();
-    return dialog_controller->GetPrintPreviewForContents(initiator_tab_);
+    return dialog_controller->GetPrintPreviewForContents(initiator_);
   }
 
  private:
@@ -143,14 +143,14 @@
     cloned_tab_observer_.reset(new PrintPreviewDialogClonedObserver(first_tab));
     chrome::DuplicateTab(browser());
 
-    initiator_tab_ = browser()->tab_strip_model()->GetActiveWebContents();
-    ASSERT_TRUE(initiator_tab_);
-    ASSERT_NE(first_tab, initiator_tab_);
+    initiator_ = browser()->tab_strip_model()->GetActiveWebContents();
+    ASSERT_TRUE(initiator_);
+    ASSERT_NE(first_tab, initiator_);
   }
 
   virtual void CleanUpOnMainThread() OVERRIDE {
     cloned_tab_observer_.reset();
-    initiator_tab_ = NULL;
+    initiator_ = NULL;
   }
 
   RequestPrintPreviewObserver* request_preview_tab_observer() {
@@ -158,13 +158,13 @@
   }
 
   scoped_ptr<PrintPreviewDialogClonedObserver> cloned_tab_observer_;
-  WebContents* initiator_tab_;
+  WebContents* initiator_;
 
   DISALLOW_COPY_AND_ASSIGN(PrintPreviewDialogControllerBrowserTest);
 };
 
-// Test to verify that when a initiator tab navigates, we can create a new
-// preview dialog for the new tab contents.
+// Test to verify that when a initiator navigates, we can create a new preview
+// dialog for the new tab contents.
 IN_PROC_BROWSER_TEST_F(PrintPreviewDialogControllerBrowserTest,
                        NavigateFromInitiatorTab) {
   // print for the first time.
@@ -175,7 +175,7 @@
 
   // Check a new print preview dialog got created.
   ASSERT_TRUE(preview_dialog);
-  ASSERT_NE(initiator_tab(), preview_dialog);
+  ASSERT_NE(initiator(), preview_dialog);
 
   // Navigate in the initiator tab. Make sure navigating destroys the print
   // preview dialog.
@@ -193,8 +193,8 @@
   EXPECT_TRUE(new_preview_dialog);
 }
 
-// Test to verify that after reloading the initiator tab, it creates a new
-// print preview dialog.
+// Test to verify that after reloading the initiator, it creates a new print
+// preview dialog.
 IN_PROC_BROWSER_TEST_F(PrintPreviewDialogControllerBrowserTest,
                        ReloadInitiatorTab) {
   // print for the first time.
@@ -204,9 +204,9 @@
 
   // Check a new print preview dialog got created.
   ASSERT_TRUE(preview_dialog);
-  ASSERT_NE(initiator_tab(), preview_dialog);
+  ASSERT_NE(initiator(), preview_dialog);
 
-  // Reload the initiator tab. Make sure reloading destroys the print preview
+  // Reload the initiator. Make sure reloading destroys the print preview
   // dialog.
   PrintPreviewDialogDestroyedObserver dialog_destroyed_observer(preview_dialog);
   content::WindowedNotificationObserver notification_observer(
diff --git a/chrome/browser/printing/print_preview_dialog_controller_unittest.cc b/chrome/browser/printing/print_preview_dialog_controller_unittest.cc
index a336631..6ec20ba 100644
--- a/chrome/browser/printing/print_preview_dialog_controller_unittest.cc
+++ b/chrome/browser/printing/print_preview_dialog_controller_unittest.cc
@@ -16,23 +16,23 @@
 
 using content::WebContents;
 
-// Test crashes on Aura due to initiator tab's native view having no parent.
+// Test crashes on Aura due to initiator's native view having no parent.
 // http://crbug.com/104284
 #if defined(USE_AURA)
 #define MAYBE_GetOrCreatePreviewDialog DISABLED_GetOrCreatePreviewDialog
 #define MAYBE_MultiplePreviewDialogs DISABLED_MultiplePreviewDialogs
-#define MAYBE_ClearInitiatorTabDetails DISABLED_ClearInitiatorTabDetails
+#define MAYBE_ClearInitiatorDetails DISABLED_ClearInitiatorDetails
 #else
 #define MAYBE_GetOrCreatePreviewDialog GetOrCreatePreviewDialog
 #define MAYBE_MultiplePreviewDialogs MultiplePreviewDialogs
-#define MAYBE_ClearInitiatorTabDetails ClearInitiatorTabDetails
+#define MAYBE_ClearInitiatorDetails ClearInitiatorDetails
 #endif
 
 namespace printing {
 
 typedef PrintPreviewTest PrintPreviewDialogControllerUnitTest;
 
-// Create/Get a preview dialog for initiator tab.
+// Create/Get a preview dialog for initiator.
 TEST_F(PrintPreviewDialogControllerUnitTest, MAYBE_GetOrCreatePreviewDialog) {
   // Lets start with one window with one tab.
   EXPECT_EQ(1u, chrome::GetTotalBrowserCount());
@@ -40,38 +40,37 @@
   chrome::NewTab(browser());
   EXPECT_EQ(1, browser()->tab_strip_model()->count());
 
-  // Create a reference to initiator tab contents.
-  WebContents* initiator_tab =
-      browser()->tab_strip_model()->GetActiveWebContents();
+  // Create a reference to initiator contents.
+  WebContents* initiator = browser()->tab_strip_model()->GetActiveWebContents();
 
   PrintPreviewDialogController* dialog_controller =
       PrintPreviewDialogController::GetInstance();
   ASSERT_TRUE(dialog_controller);
 
-  // Get the preview dialog for initiator tab.
-  PrintViewManager::FromWebContents(initiator_tab)->PrintPreviewNow(false);
+  // Get the preview dialog for initiator.
+  PrintViewManager::FromWebContents(initiator)->PrintPreviewNow(false);
   WebContents* preview_dialog =
-      dialog_controller->GetOrCreatePreviewDialog(initiator_tab);
+      dialog_controller->GetOrCreatePreviewDialog(initiator);
 
   // New print preview dialog is a constrained window, so the number of tabs is
   // still 1.
   EXPECT_EQ(1, browser()->tab_strip_model()->count());
-  EXPECT_NE(initiator_tab, preview_dialog);
+  EXPECT_NE(initiator, preview_dialog);
 
-  // Get the print preview dialog for the same initiator tab.
+  // Get the print preview dialog for the same initiator.
   WebContents* new_preview_dialog =
-      dialog_controller->GetOrCreatePreviewDialog(initiator_tab);
+      dialog_controller->GetOrCreatePreviewDialog(initiator);
 
   // Preview dialog already exists. Tab count remains the same.
   EXPECT_EQ(1, browser()->tab_strip_model()->count());
 
-  // 1:1 relationship between initiator tab and preview dialog.
+  // 1:1 relationship between initiator and preview dialog.
   EXPECT_EQ(new_preview_dialog, preview_dialog);
 }
 
-// Tests multiple print preview dialogs exist in the same browser for
-// different initiator tabs. If a preview dialog already exists for an
-// initiator tab, that initiator tab gets focused.
+// Tests multiple print preview dialogs exist in the same browser for different
+// initiators. If a preview dialog already exists for an initiator, that
+// initiator gets focused.
 TEST_F(PrintPreviewDialogControllerUnitTest, MAYBE_MultiplePreviewDialogs) {
   // Lets start with one window and two tabs.
   EXPECT_EQ(1u, chrome::GetTotalBrowserCount());
@@ -80,7 +79,7 @@
 
   EXPECT_EQ(0, tab_strip_model->count());
 
-  // Create some new initiator tabs.
+  // Create some new initiators.
   chrome::NewTab(browser());
   WebContents* web_contents_1 = tab_strip_model->GetActiveWebContents();
   ASSERT_TRUE(web_contents_1);
@@ -109,8 +108,8 @@
 
   EXPECT_NE(web_contents_2, preview_dialog_2);
   EXPECT_NE(preview_dialog_1, preview_dialog_2);
-  // 2 initiator tabs and 2 preview dialogs exist in the same browser.
-  // The preview dialogs are constrained in their respective initiator tabs.
+  // 2 initiators and 2 preview dialogs exist in the same browser.  The preview
+  // dialogs are constrained in their respective initiators.
   EXPECT_EQ(2, tab_strip_model->count());
 
   int tab_1_index = tab_strip_model->GetIndexOfWebContents(web_contents_1);
@@ -125,7 +124,7 @@
   EXPECT_EQ(-1, preview_dialog_2_index);
 
   // Since |preview_dialog_2_index| was the most recently created dialog, its
-  // initiator tab should have focus.
+  // initiator should have focus.
   EXPECT_EQ(tab_2_index, tab_strip_model->active_index());
 
   // When we get the preview dialog for |web_contents_1|,
@@ -134,39 +133,38 @@
   EXPECT_EQ(tab_1_index, tab_strip_model->active_index());
 }
 
-// Check clearing the initiator tab details associated with a print preview
-// dialog allows the initiator tab to create another print preview dialog.
-TEST_F(PrintPreviewDialogControllerUnitTest, MAYBE_ClearInitiatorTabDetails) {
+// Check clearing the initiator details associated with a print preview dialog
+// allows the initiator to create another print preview dialog.
+TEST_F(PrintPreviewDialogControllerUnitTest, MAYBE_ClearInitiatorDetails) {
   // Lets start with one window with one tab.
   EXPECT_EQ(1u, chrome::GetTotalBrowserCount());
   EXPECT_EQ(0, browser()->tab_strip_model()->count());
   chrome::NewTab(browser());
   EXPECT_EQ(1, browser()->tab_strip_model()->count());
 
-  // Create a reference to initiator tab contents.
-  WebContents* initiator_tab =
-      browser()->tab_strip_model()->GetActiveWebContents();
+  // Create a reference to initiator contents.
+  WebContents* initiator = browser()->tab_strip_model()->GetActiveWebContents();
 
   PrintPreviewDialogController* dialog_controller =
       PrintPreviewDialogController::GetInstance();
   ASSERT_TRUE(dialog_controller);
 
-  // Get the preview dialog for the initiator tab.
-  PrintViewManager::FromWebContents(initiator_tab)->PrintPreviewNow(false);
+  // Get the preview dialog for the initiator.
+  PrintViewManager::FromWebContents(initiator)->PrintPreviewNow(false);
   WebContents* preview_dialog =
-      dialog_controller->GetOrCreatePreviewDialog(initiator_tab);
+      dialog_controller->GetOrCreatePreviewDialog(initiator);
 
   // New print preview dialog is a constrained window, so the number of tabs is
   // still 1.
   EXPECT_EQ(1, browser()->tab_strip_model()->count());
-  EXPECT_NE(initiator_tab, preview_dialog);
+  EXPECT_NE(initiator, preview_dialog);
 
-  // Clear the initiator tab details associated with the preview dialog.
-  dialog_controller->EraseInitiatorTabInfo(preview_dialog);
+  // Clear the initiator details associated with the preview dialog.
+  dialog_controller->EraseInitiatorInfo(preview_dialog);
 
-  // Get a new print preview dialog for the initiator tab.
+  // Get a new print preview dialog for the initiator.
   WebContents* new_preview_dialog =
-      dialog_controller->GetOrCreatePreviewDialog(initiator_tab);
+      dialog_controller->GetOrCreatePreviewDialog(initiator);
 
   // New print preview dialog is a constrained window, so the number of tabs is
   // still 1.
diff --git a/chrome/browser/printing/print_preview_test.cc b/chrome/browser/printing/print_preview_test.cc
index 4733668..e6136a1 100644
--- a/chrome/browser/printing/print_preview_test.cc
+++ b/chrome/browser/printing/print_preview_test.cc
@@ -76,8 +76,8 @@
 
   // The PluginService will be destroyed at the end of the test (due to the
   // ShadowingAtExitManager in our base class).
-  content::PluginService::GetInstance()->SetPluginListForTesting(
-      &plugin_list_);
+  content::PluginService::GetInstance()->Init();
+  content::PluginService::GetInstance()->DisablePluginsDiscoveryForTesting();
 
   profile()->GetPrefs()->SetBoolean(prefs::kPrintPreviewDisabled, false);
 }
diff --git a/chrome/browser/printing/print_preview_test.h b/chrome/browser/printing/print_preview_test.h
index f1c6ab5..ddfee0e 100644
--- a/chrome/browser/printing/print_preview_test.h
+++ b/chrome/browser/printing/print_preview_test.h
@@ -6,7 +6,6 @@
 #define CHROME_BROWSER_PRINTING_PRINT_PREVIEW_TEST_H_
 
 #include "chrome/test/base/browser_with_test_window_test.h"
-#include "webkit/plugins/npapi/mock_plugin_list.h"
 
 class PrintPreviewTest : public BrowserWithTestWindowTest {
  public:
@@ -20,8 +19,6 @@
   virtual BrowserWindow* CreateBrowserWindow() OVERRIDE;
 
  private:
-  webkit::npapi::MockPluginList plugin_list_;
-
   DISALLOW_COPY_AND_ASSIGN(PrintPreviewTest);
 };
 
diff --git a/chrome/browser/printing/print_view_manager.h b/chrome/browser/printing/print_view_manager.h
index 55b4708..616ff00 100644
--- a/chrome/browser/printing/print_view_manager.h
+++ b/chrome/browser/printing/print_view_manager.h
@@ -46,7 +46,7 @@
   bool PrintForSystemDialogNow();
 
   // Same as PrintNow(), but for the case where a user press "ctrl+shift+p" to
-  // show the native system dialog. This can happen from both initiator tab and
+  // show the native system dialog. This can happen from both initiator and
   // preview dialog.
   bool AdvancedPrintNow();
 
diff --git a/chrome/browser/profile_resetter/profile_resetter.cc b/chrome/browser/profile_resetter/profile_resetter.cc
index 297e359..3c797a7 100644
--- a/chrome/browser/profile_resetter/profile_resetter.cc
+++ b/chrome/browser/profile_resetter/profile_resetter.cc
@@ -123,7 +123,8 @@
       ListPrefUpdate update(prefs, prefs::kSearchProviderOverrides);
       update->Swap(search_engines.get());
     }
-    template_url_service_->ResetNonExtensionURLs();
+
+    template_url_service_->ResetURLs();
 
     // Reset Google search URL.
     prefs->ClearPref(prefs::kLastPromptedGoogleURL);
diff --git a/chrome/browser/profile_resetter/profile_resetter_test_base.cc b/chrome/browser/profile_resetter/profile_resetter_test_base.cc
index a4c4cf4..85b4ef7 100644
--- a/chrome/browser/profile_resetter/profile_resetter_test_base.cc
+++ b/chrome/browser/profile_resetter/profile_resetter_test_base.cc
@@ -14,6 +14,7 @@
   EXPECT_CALL(*this, Callback());
   runner_ = new content::MessageLoopRunner;
   runner_->Run();
+  runner_ = NULL;
 }
 
 void ProfileResetterMockObject::StopLoop() {
diff --git a/chrome/browser/profile_resetter/profile_resetter_unittest.cc b/chrome/browser/profile_resetter/profile_resetter_unittest.cc
index 32442f9..f1caa33 100644
--- a/chrome/browser/profile_resetter/profile_resetter_unittest.cc
+++ b/chrome/browser/profile_resetter/profile_resetter_unittest.cc
@@ -15,7 +15,7 @@
 #include "chrome/browser/profile_resetter/brandcode_config_fetcher.h"
 #include "chrome/browser/profile_resetter/profile_resetter_test_base.h"
 #include "chrome/browser/search_engines/template_url_service.h"
-#include "chrome/browser/search_engines/template_url_service_test_util.h"
+#include "chrome/browser/search_engines/template_url_service_factory.h"
 #include "chrome/browser/themes/theme_service.h"
 #include "chrome/browser/themes/theme_service_factory.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
@@ -72,36 +72,33 @@
 using extensions::Extension;
 using extensions::Manifest;
 
-class ProfileResetterTest : public testing::Test,
+// ProfileResetterTest sets up the extension, WebData and TemplateURL services.
+class ProfileResetterTest : public ExtensionServiceTestBase,
                             public ProfileResetterTestBase {
  protected:
-  // testing::Test:
   virtual void SetUp() OVERRIDE;
-  virtual void TearDown() OVERRIDE;
 
-  TemplateURLServiceTestUtil test_util_;
+  TestingProfile* profile() { return profile_.get(); }
+
+  static BrowserContextKeyedService* CreateTemplateURLService(
+      content::BrowserContext* context);
 };
 
 void ProfileResetterTest::SetUp() {
-  test_util_.SetUp();
-  resetter_.reset(new ProfileResetter(test_util_.profile()));
-}
-
-void ProfileResetterTest::TearDown() {
-  test_util_.TearDown();
-}
-
-// ExtensionsResetTest sets up the extension service.
-class ExtensionsResetTest : public ExtensionServiceTestBase,
-                            public ProfileResetterTestBase {
- protected:
-  virtual void SetUp() OVERRIDE;
-};
-
-void ExtensionsResetTest::SetUp() {
   ExtensionServiceTestBase::SetUp();
   InitializeEmptyExtensionService();
-  resetter_.reset(new ProfileResetter(profile_.get()));
+
+  profile()->CreateWebDataService();
+  TemplateURLServiceFactory::GetInstance()->SetTestingFactory(
+      profile(),
+      &ProfileResetterTest::CreateTemplateURLService);
+  resetter_.reset(new ProfileResetter(profile()));
+}
+
+// static
+BrowserContextKeyedService* ProfileResetterTest::CreateTemplateURLService(
+    content::BrowserContext* context) {
+  return new TemplateURLService(static_cast<Profile*>(context));
 }
 
 scoped_refptr<Extension> CreateExtension(const std::string& name,
@@ -113,7 +110,8 @@
   manifest.SetString(extension_manifest_keys::kName, name);
   manifest.SetString("app.launch.web_url", "http://www.google.com");
   if (theme)
-    manifest.Set(extension_manifest_keys::kTheme, new DictionaryValue());
+    manifest.Set(extension_manifest_keys::kTheme, new DictionaryValue);
+  manifest.SetString(extension_manifest_keys::kOmniboxKeyword, name);
   std::string error;
   scoped_refptr<Extension> extension = Extension::Create(
       path,
@@ -211,25 +209,42 @@
 
 TEST_F(ProfileResetterTest, ResetDefaultSearchEngine) {
   // Search engine's logic is tested by
-  // TemplateURLServiceTest.ResetNonExtensionURLs.
-  PrefService* prefs = test_util_.profile()->GetPrefs();
+  // TemplateURLServiceTest.ResetURLs.
+  PrefService* prefs = profile()->GetPrefs();
   DCHECK(prefs);
   prefs->SetString(prefs::kLastPromptedGoogleURL, "http://www.foo.com/");
 
+  scoped_refptr<Extension> extension = CreateExtension(
+      "xxx",
+      base::FilePath(FILE_PATH_LITERAL("//nonexistent")),
+      Manifest::COMPONENT,
+      false);
+  service_->AddExtension(extension.get());
+
   ResetAndWait(ProfileResetter::DEFAULT_SEARCH_ENGINE);
 
+  // TemplateURLService should reset extension search engines.
+  TemplateURLService* model =
+      TemplateURLServiceFactory::GetForProfile(profile());
+  TemplateURL* ext_url = model->GetTemplateURLForKeyword(ASCIIToUTF16("xxx"));
+  ASSERT_TRUE(ext_url);
+  EXPECT_TRUE(ext_url->IsExtensionKeyword());
+  EXPECT_EQ(ASCIIToUTF16("xxx"), ext_url->keyword());
+  EXPECT_EQ(ASCIIToUTF16("xxx"), ext_url->short_name());
   EXPECT_EQ("", prefs->GetString(prefs::kLastPromptedGoogleURL));
 }
 
 TEST_F(ProfileResetterTest, ResetDefaultSearchEngineNonOrganic) {
-  PrefService* prefs = test_util_.profile()->GetPrefs();
+  PrefService* prefs = profile()->GetPrefs();
   DCHECK(prefs);
   prefs->SetString(prefs::kLastPromptedGoogleURL, "http://www.foo.com/");
 
   ResetAndWait(ProfileResetter::DEFAULT_SEARCH_ENGINE, kDistributionConfig);
 
-  EXPECT_EQ(1u, test_util_.model()->GetTemplateURLs().size());
-  TemplateURL* default_engine = test_util_.model()->GetDefaultSearchProvider();
+  TemplateURLService* model =
+      TemplateURLServiceFactory::GetForProfile(profile());
+  EXPECT_EQ(1u, model->GetTemplateURLs().size());
+  TemplateURL* default_engine = model->GetDefaultSearchProvider();
   ASSERT_NE(static_cast<TemplateURL*>(NULL), default_engine);
   EXPECT_EQ(ASCIIToUTF16("first"), default_engine->short_name());
   EXPECT_EQ(ASCIIToUTF16("firstkey"), default_engine->keyword());
@@ -239,7 +254,7 @@
 }
 
 TEST_F(ProfileResetterTest, ResetHomepage) {
-  PrefService* prefs = test_util_.profile()->GetPrefs();
+  PrefService* prefs = profile()->GetPrefs();
   DCHECK(prefs);
   prefs->SetBoolean(prefs::kHomePageIsNewTabPage, false);
   prefs->SetString(prefs::kHomePage, "http://google.com");
@@ -253,7 +268,7 @@
 }
 
 TEST_F(ProfileResetterTest, ResetHomepageNonOrganic) {
-  PrefService* prefs = test_util_.profile()->GetPrefs();
+  PrefService* prefs = profile()->GetPrefs();
   DCHECK(prefs);
   prefs->SetBoolean(prefs::kHomePageIsNewTabPage, true);
   prefs->SetString(prefs::kHomePage, "http://google.com");
@@ -268,9 +283,9 @@
 
 TEST_F(ProfileResetterTest, ResetContentSettings) {
   HostContentSettingsMap* host_content_settings_map =
-      test_util_.profile()->GetHostContentSettingsMap();
+      profile()->GetHostContentSettingsMap();
   DesktopNotificationService* notification_service =
-      DesktopNotificationServiceFactory::GetForProfile(test_util_.profile());
+      DesktopNotificationServiceFactory::GetForProfile(profile());
   ContentSettingsPattern pattern =
       ContentSettingsPattern::FromString("[*.]example.org");
   std::map<ContentSettingsType, ContentSetting> default_settings;
@@ -297,7 +312,7 @@
           default_setting == CONTENT_SETTING_ALLOW ? CONTENT_SETTING_ALLOW
                                                    : CONTENT_SETTING_BLOCK;
       if (HostContentSettingsMap::IsSettingAllowedForType(
-              test_util_.profile()->GetPrefs(),
+              profile()->GetPrefs(),
               wildcard_setting,
               content_type)) {
         host_content_settings_map->SetDefaultContentSetting(
@@ -306,7 +321,7 @@
       }
       if (!HostContentSettingsMap::ContentTypeHasCompoundValue(content_type) &&
           HostContentSettingsMap::IsSettingAllowedForType(
-              test_util_.profile()->GetPrefs(),
+              profile()->GetPrefs(),
               site_setting,
               content_type)) {
         host_content_settings_map->SetContentSetting(
@@ -361,7 +376,7 @@
   }
 }
 
-TEST_F(ExtensionsResetTest, ResetExtensionsByDisabling) {
+TEST_F(ProfileResetterTest, ResetExtensionsByDisabling) {
   base::ScopedTempDir temp_dir;
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
 
@@ -374,7 +389,7 @@
 
   // ThemeService isn't compiled for Android.
   ThemeService* theme_service =
-      ThemeServiceFactory::GetForProfile(profile_.get());
+      ThemeServiceFactory::GetForProfile(profile());
   EXPECT_FALSE(theme_service->UsingDefaultTheme());
 
   scoped_refptr<Extension> ext2 = CreateExtension(
@@ -406,7 +421,7 @@
   EXPECT_TRUE(theme_service->UsingDefaultTheme());
 }
 
-TEST_F(ExtensionsResetTest, ResetExtensionsByDisablingNonOrganic) {
+TEST_F(ProfileResetterTest, ResetExtensionsByDisablingNonOrganic) {
   scoped_refptr<Extension> ext2 = CreateExtension(
       "example2",
       base::FilePath(FILE_PATH_LITERAL("//nonexistent")),
@@ -432,7 +447,7 @@
 }
 
 TEST_F(ProfileResetterTest, ResetStartPage) {
-  PrefService* prefs = test_util_.profile()->GetPrefs();
+  PrefService* prefs = profile()->GetPrefs();
   DCHECK(prefs);
 
   SessionStartupPref startup_pref(SessionStartupPref::URLS);
@@ -448,7 +463,7 @@
 }
 
 TEST_F(ProfileResetterTest, ResetStartPageNonOrganic) {
-  PrefService* prefs = test_util_.profile()->GetPrefs();
+  PrefService* prefs = profile()->GetPrefs();
   DCHECK(prefs);
 
   SessionStartupPref startup_pref(SessionStartupPref::LAST);
@@ -502,7 +517,8 @@
 TEST_F(ProfileResetterTest, ResetFewFlags) {
   // mock_object_ is a StrictMock, so we verify that it is called only once.
   ResetAndWait(ProfileResetter::DEFAULT_SEARCH_ENGINE |
-               ProfileResetter::HOMEPAGE);
+               ProfileResetter::HOMEPAGE |
+               ProfileResetter::CONTENT_SETTINGS);
 }
 
 // Tries to load unavailable config file.
diff --git a/chrome/browser/profiles/avatar_menu_model.cc b/chrome/browser/profiles/avatar_menu_model.cc
index 55e2b89..de6b904 100644
--- a/chrome/browser/profiles/avatar_menu_model.cc
+++ b/chrome/browser/profiles/avatar_menu_model.cc
@@ -12,6 +12,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/prefs/incognito_mode_prefs.h"
 #include "chrome/browser/profiles/avatar_menu_model_observer.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_info_cache.h"
@@ -62,6 +63,16 @@
   }
 }
 
+void OnGuestProfileCreated(bool always_create,
+                           chrome::HostDesktopType desktop_type,
+                           Profile* profile,
+                           Profile::CreateStatus status) {
+  IncognitoModePrefs::SetAvailability(
+      profile->GetPrefs(),
+      IncognitoModePrefs::FORCED);
+  OnProfileCreated(always_create, desktop_type, profile, status);
+}
+
 // Constants for the show profile switcher experiment
 const char kShowProfileSwitcherFieldTrialName[] = "ShowProfileSwitcher";
 const char kAlwaysShowSwitcherGroupName[] = "AlwaysShow";
@@ -152,15 +163,7 @@
   if (browser_)
     desktop_type = browser_->host_desktop_type();
 
-  g_browser_process->profile_manager()->CreateProfileAsync(
-      path,
-      base::Bind(&OnProfileCreated,
-                 always_create,
-                 desktop_type),
-      string16(),
-      string16(),
-      false);
-
+  profiles::SwitchToProfile(path, desktop_type, always_create);
   ProfileMetrics::LogProfileSwitchUser(ProfileMetrics::SWITCH_PROFILE_ICON);
 }
 
@@ -198,7 +201,7 @@
 void AvatarMenuModel::SwitchToGuestProfileWindow(Browser* browser) {
   ProfileManager* profile_manager = g_browser_process->profile_manager();
   profile_manager->CreateProfileAsync(ProfileManager::GetGuestProfilePath(),
-                                      base::Bind(&OnProfileCreated,
+                                      base::Bind(&OnGuestProfileCreated,
                                                  false,
                                                  browser->host_desktop_type()),
                                       string16(),
diff --git a/chrome/browser/profiles/avatar_menu_model_browsertest.cc b/chrome/browser/profiles/avatar_menu_model_browsertest.cc
index b980ef3..f7bed7b 100644
--- a/chrome/browser/profiles/avatar_menu_model_browsertest.cc
+++ b/chrome/browser/profiles/avatar_menu_model_browsertest.cc
@@ -17,6 +17,14 @@
 
 namespace {
 
+// An observer that returns back to test code after a new profile is
+// initialized.
+void OnUnblockOnProfileCreation(Profile* profile,
+                                Profile::CreateStatus status) {
+  if (status == Profile::CREATE_STATUS_INITIALIZED)
+    base::MessageLoop::current()->Quit();
+}
+
 typedef InProcessBrowserTest AvatarMenuModelTest;
 
 IN_PROC_BROWSER_TEST_F(AvatarMenuModelTest, SignOut) {
@@ -46,4 +54,48 @@
   EXPECT_EQ(0U, browser_list->size());
 }
 
+IN_PROC_BROWSER_TEST_F(AvatarMenuModelTest, SwitchToProfile) {
+  if (!profiles::IsMultipleProfilesEnabled())
+    return;
+
+  ProfileManager* profile_manager = g_browser_process->profile_manager();
+  Profile* current_profile = browser()->profile();
+  ProfileInfoCache& cache = profile_manager->GetProfileInfoCache();
+  base::FilePath path_profile1 = current_profile->GetPath();
+  base::FilePath user_dir = cache.GetUserDataDir();
+
+  // Create an additional profile.
+  base::FilePath path_profile2 = user_dir.Append(
+      FILE_PATH_LITERAL("New Profile 2"));
+  profile_manager->CreateProfileAsync(path_profile2,
+                                      base::Bind(&OnUnblockOnProfileCreation),
+                                      string16(), string16(), false);
+
+  // Spin to allow profile creation to take place, loop is terminated
+  // by OnUnblockOnProfileCreation when the profile is created.
+  content::RunMessageLoop();
+  ASSERT_EQ(cache.GetNumberOfProfiles(), 2U);
+
+  AvatarMenuModel model(&cache, NULL, browser());
+  BrowserList* browser_list =
+      BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_NATIVE);
+  EXPECT_EQ(1U, browser_list->size());
+  EXPECT_EQ(path_profile1, browser_list->get(0)->profile()->GetPath());
+
+  // Open a browser window for the first profile.
+  model.SwitchToProfile(cache.GetIndexOfProfileWithPath(path_profile1), false);
+  EXPECT_EQ(1U, browser_list->size());
+  EXPECT_EQ(path_profile1, browser_list->get(0)->profile()->GetPath());
+
+  // Open a browser window for the second profile.
+  model.SwitchToProfile(cache.GetIndexOfProfileWithPath(path_profile2), false);
+  EXPECT_EQ(2U, browser_list->size());
+
+  // Switch to the first profile without opening a new window.
+  model.SwitchToProfile(cache.GetIndexOfProfileWithPath(path_profile1), false);
+  EXPECT_EQ(2U, browser_list->size());
+  EXPECT_EQ(path_profile1, browser_list->get(0)->profile()->GetPath());
+  EXPECT_EQ(path_profile2, browser_list->get(1)->profile()->GetPath());
+
+}
 }  // namespace
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 bd26711..38b80e9 100644
--- a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
+++ b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
@@ -39,6 +39,7 @@
 #include "chrome/browser/extensions/api/management/management_api.h"
 #include "chrome/browser/extensions/api/media_galleries_private/media_galleries_private_api.h"
 #include "chrome/browser/extensions/api/omnibox/omnibox_api.h"
+#include "chrome/browser/extensions/api/preference/chrome_direct_setting_api.h"
 #include "chrome/browser/extensions/api/preference/preference_api.h"
 #include "chrome/browser/extensions/api/processes/processes_api.h"
 #include "chrome/browser/extensions/api/push_messaging/push_messaging_api.h"
@@ -198,6 +199,7 @@
   extensions::AudioAPI::GetFactoryInstance();
   extensions::BookmarksAPI::GetFactoryInstance();
   extensions::BluetoothAPIFactory::GetInstance();
+  extensions::chromedirectsetting::ChromeDirectSettingAPI::GetFactoryInstance();
   extensions::CommandService::GetFactoryInstance();
   extensions::CookiesAPI::GetFactoryInstance();
   extensions::DeveloperPrivateAPIFactory::GetInstance();
diff --git a/chrome/browser/profiles/off_the_record_profile_impl.cc b/chrome/browser/profiles/off_the_record_profile_impl.cc
index 931ed9a..3228c41 100644
--- a/chrome/browser/profiles/off_the_record_profile_impl.cc
+++ b/chrome/browser/profiles/off_the_record_profile_impl.cc
@@ -28,6 +28,7 @@
 #include "chrome/browser/geolocation/chrome_geolocation_permission_context.h"
 #include "chrome/browser/geolocation/chrome_geolocation_permission_context_factory.h"
 #include "chrome/browser/io_thread.h"
+#include "chrome/browser/net/pref_proxy_config_tracker.h"
 #include "chrome/browser/net/proxy_service_factory.h"
 #include "chrome/browser/plugins/chrome_plugin_service_filter.h"
 #include "chrome/browser/plugins/plugin_prefs.h"
@@ -54,13 +55,13 @@
 #include "webkit/browser/database/database_tracker.h"
 
 #if defined(OS_ANDROID) || defined(OS_IOS)
+#include "chrome/browser/prefs/proxy_prefs.h"
 #include "chrome/browser/prefs/scoped_user_pref_update.h"
 #endif  // defined(OS_ANDROID) || defined(OS_IOS)
 
 #if defined(OS_CHROMEOS)
 #include "chrome/browser/chromeos/preferences.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
-#include "chrome/browser/chromeos/proxy_config_service_impl.h"
 #endif
 
 using content::BrowserThread;
diff --git a/chrome/browser/profiles/off_the_record_profile_io_data.cc b/chrome/browser/profiles/off_the_record_profile_io_data.cc
index d6f546a..842204e 100644
--- a/chrome/browser/profiles/off_the_record_profile_io_data.cc
+++ b/chrome/browser/profiles/off_the_record_profile_io_data.cc
@@ -190,7 +190,9 @@
       io_thread_globals->throttler_manager.get());
 
   // For incognito, we use the default non-persistent HttpServerPropertiesImpl.
-  set_http_server_properties(new net::HttpServerPropertiesImpl);
+  set_http_server_properties(
+      scoped_ptr<net::HttpServerProperties>(
+          new net::HttpServerPropertiesImpl()));
   main_context->set_http_server_properties(http_server_properties());
 
   // For incognito, we use a non-persistent server bound cert store.
diff --git a/chrome/browser/profiles/profile.cc b/chrome/browser/profiles/profile.cc
index 93415c7..c8690ee 100644
--- a/chrome/browser/profiles/profile.cc
+++ b/chrome/browser/profiles/profile.cc
@@ -116,6 +116,10 @@
       prefs::kSpeechRecognitionFilterProfanities,
       true,
       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
+  registry->RegisterIntegerPref(
+      prefs::kProfileIconVersion,
+      0,
+      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
 #if defined(OS_CHROMEOS)
   // TODO(dilmah): For OS_CHROMEOS we maintain kApplicationLocale in both
   // local state and user's profile.  For other platforms we maintain
diff --git a/chrome/browser/profiles/profile.h b/chrome/browser/profiles/profile.h
index 19a232a..1e5270b 100644
--- a/chrome/browser/profiles/profile.h
+++ b/chrome/browser/profiles/profile.h
@@ -12,7 +12,6 @@
 #include "base/basictypes.h"
 #include "base/containers/hash_tables.h"
 #include "base/logging.h"
-#include "chrome/browser/net/pref_proxy_config_tracker.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/content_browser_client.h"
 #include "net/url_request/url_request_job_factory.h"
@@ -23,6 +22,8 @@
 class FaviconService;
 class HostContentSettingsMap;
 class PasswordStore;
+class PrefProxyConfigTracker;
+class PrefService;
 class PromoCounter;
 class ProtocolHandlerRegistry;
 class TestingProfile;
diff --git a/chrome/browser/profiles/profile_impl.cc b/chrome/browser/profiles/profile_impl.cc
index b4ef81e..57ffb8f 100644
--- a/chrome/browser/profiles/profile_impl.cc
+++ b/chrome/browser/profiles/profile_impl.cc
@@ -48,6 +48,7 @@
 #include "chrome/browser/net/chrome_url_request_context.h"
 #include "chrome/browser/net/net_pref_observer.h"
 #include "chrome/browser/net/predictor.h"
+#include "chrome/browser/net/pref_proxy_config_tracker.h"
 #include "chrome/browser/net/proxy_service_factory.h"
 #include "chrome/browser/net/ssl_config_service_manager.h"
 #include "chrome/browser/net/url_fixer_upper.h"
@@ -104,7 +105,6 @@
 #include "chrome/browser/chromeos/login/user_manager.h"
 #include "chrome/browser/chromeos/preferences.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
-#include "chrome/browser/chromeos/proxy_config_service_impl.h"
 #endif
 
 #if defined(ENABLE_CONFIGURATION_POLICY)
diff --git a/chrome/browser/profiles/profile_impl_io_data.cc b/chrome/browser/profiles/profile_impl_io_data.cc
index ee68a4d..bbe1142 100644
--- a/chrome/browser/profiles/profile_impl_io_data.cc
+++ b/chrome/browser/profiles/profile_impl_io_data.cc
@@ -291,7 +291,8 @@
   io_data_->http_server_properties_manager_ =
       new chrome_browser_net::HttpServerPropertiesManager(pref_service);
   io_data_->set_http_server_properties(
-      io_data_->http_server_properties_manager_);
+      scoped_ptr<net::HttpServerProperties>(
+          io_data_->http_server_properties_manager_));
   io_data_->session_startup_pref()->Init(
       prefs::kRestoreOnStartup, pref_service);
   io_data_->session_startup_pref()->MoveToThread(
diff --git a/chrome/browser/profiles/profile_io_data.cc b/chrome/browser/profiles/profile_io_data.cc
index 8335fa5..e7b2cfb 100644
--- a/chrome/browser/profiles/profile_io_data.cc
+++ b/chrome/browser/profiles/profile_io_data.cc
@@ -11,6 +11,7 @@
 #include "base/bind_helpers.h"
 #include "base/command_line.h"
 #include "base/compiler_specific.h"
+#include "base/debug/alias.h"
 #include "base/logging.h"
 #include "base/path_service.h"
 #include "base/prefs/pref_service.h"
@@ -85,7 +86,6 @@
 #if defined(OS_CHROMEOS)
 #include "chrome/browser/chromeos/drive/drive_protocol_handler.h"
 #include "chrome/browser/chromeos/policy/policy_cert_verifier.h"
-#include "chrome/browser/chromeos/proxy_config_service_impl.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"
@@ -260,11 +260,9 @@
   params->protocol_handler_interceptor =
       protocol_handler_registry->CreateJobInterceptorFactory();
 
-  ChromeProxyConfigService* proxy_config_service =
-      ProxyServiceFactory::CreateProxyConfigService();
-  params->proxy_config_service.reset(proxy_config_service);
-  profile->GetProxyConfigTracker()->SetChromeProxyConfigService(
-      proxy_config_service);
+  params->proxy_config_service
+      .reset(ProxyServiceFactory::CreateProxyConfigService(
+           profile->GetProxyConfigTracker()));
 #if defined(ENABLE_MANAGED_USERS)
   ManagedUserService* managed_user_service =
       ManagedUserServiceFactory::GetForProfile(profile);
@@ -409,20 +407,80 @@
   if (BrowserThread::IsMessageLoopValid(BrowserThread::IO))
     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
 
+  // Pull the contents of the request context maps onto the stack for sanity
+  // checking of values in a minidump. http://crbug.com/260425
+  size_t num_app_contexts = app_request_context_map_.size();
+  size_t num_media_contexts = isolated_media_request_context_map_.size();
+  size_t current_context = 0;
+  static const size_t kMaxCachedContexts = 20;
+  ChromeURLRequestContext* app_context_cache[kMaxCachedContexts] = {0};
+  void* app_context_vtable_cache[kMaxCachedContexts] = {0};
+  ChromeURLRequestContext* media_context_cache[kMaxCachedContexts] = {0};
+  void* media_context_vtable_cache[kMaxCachedContexts] = {0};
+  void* tmp_vtable = NULL;
+  base::debug::Alias(&num_app_contexts);
+  base::debug::Alias(&num_media_contexts);
+  base::debug::Alias(&current_context);
+  base::debug::Alias(app_context_cache);
+  base::debug::Alias(app_context_vtable_cache);
+  base::debug::Alias(media_context_cache);
+  base::debug::Alias(media_context_vtable_cache);
+  base::debug::Alias(&tmp_vtable);
+
+  current_context = 0;
+  for (URLRequestContextMap::const_iterator it =
+           app_request_context_map_.begin();
+       current_context < kMaxCachedContexts &&
+           it != app_request_context_map_.end();
+       ++it, ++current_context) {
+    app_context_cache[current_context] = it->second;
+    memcpy(&app_context_vtable_cache[current_context],
+           static_cast<void*>(it->second), sizeof(void*));
+  }
+
+  current_context = 0;
+  for (URLRequestContextMap::const_iterator it =
+           isolated_media_request_context_map_.begin();
+       current_context < kMaxCachedContexts &&
+           it != isolated_media_request_context_map_.end();
+       ++it, ++current_context) {
+    media_context_cache[current_context] = it->second;
+    memcpy(&media_context_vtable_cache[current_context],
+           static_cast<void*>(it->second), sizeof(void*));
+  }
+
+  // TODO(ajwong): These AssertNoURLRequests() calls are unnecessary since they
+  // are already done in the URLRequestContext destructor.
   if (main_request_context_)
     main_request_context_->AssertNoURLRequests();
   if (extensions_request_context_)
     extensions_request_context_->AssertNoURLRequests();
+
+  current_context = 0;
   for (URLRequestContextMap::iterator it = app_request_context_map_.begin();
        it != app_request_context_map_.end(); ++it) {
+    if (current_context < kMaxCachedContexts) {
+      CHECK_EQ(app_context_cache[current_context], it->second);
+      memcpy(&tmp_vtable, static_cast<void*>(it->second), sizeof(void*));
+      CHECK_EQ(app_context_vtable_cache[current_context], tmp_vtable);
+    }
     it->second->AssertNoURLRequests();
     delete it->second;
+    current_context++;
   }
+
+  current_context = 0;
   for (URLRequestContextMap::iterator it =
            isolated_media_request_context_map_.begin();
        it != isolated_media_request_context_map_.end(); ++it) {
+    if (current_context < kMaxCachedContexts) {
+      CHECK_EQ(media_context_cache[current_context], it->second);
+      memcpy(&tmp_vtable, static_cast<void*>(it->second), sizeof(void*));
+      CHECK_EQ(media_context_vtable_cache[current_context], tmp_vtable);
+    }
     it->second->AssertNoURLRequests();
     delete it->second;
+    current_context++;
   }
 }
 
@@ -596,13 +654,14 @@
 #endif  // defined(OS_CHROMEOS)
 }
 
-net::HttpServerProperties* ProfileIOData::http_server_properties() const {
-  return http_server_properties_.get();
+base::WeakPtr<net::HttpServerProperties>
+ProfileIOData::http_server_properties() const {
+  return http_server_properties_->GetWeakPtr();
 }
 
 void ProfileIOData::set_http_server_properties(
-    net::HttpServerProperties* http_server_properties) const {
-  http_server_properties_.reset(http_server_properties);
+    scoped_ptr<net::HttpServerProperties> http_server_properties) const {
+  http_server_properties_ = http_server_properties.Pass();
 }
 
 ProfileIOData::ResourceContext::ResourceContext(ProfileIOData* io_data)
diff --git a/chrome/browser/profiles/profile_io_data.h b/chrome/browser/profiles/profile_io_data.h
index c472b3f..1bb562b 100644
--- a/chrome/browser/profiles/profile_io_data.h
+++ b/chrome/browser/profiles/profile_io_data.h
@@ -319,10 +319,10 @@
     return proxy_service_.get();
   }
 
-  net::HttpServerProperties* http_server_properties() const;
+  base::WeakPtr<net::HttpServerProperties> http_server_properties() const;
 
   void set_http_server_properties(
-      net::HttpServerProperties* http_server_properties) const;
+      scoped_ptr<net::HttpServerProperties> http_server_properties) const;
 
   ChromeURLRequestContext* main_request_context() const {
     return main_request_context_.get();
diff --git a/chrome/browser/profiles/profile_manager.h b/chrome/browser/profiles/profile_manager.h
index dea43de..4068c88 100644
--- a/chrome/browser/profiles/profile_manager.h
+++ b/chrome/browser/profiles/profile_manager.h
@@ -234,6 +234,7 @@
  private:
   friend class TestingProfileManager;
   FRIEND_TEST_ALL_PREFIXES(ProfileManagerBrowserTest, DeleteAllProfiles);
+  FRIEND_TEST_ALL_PREFIXES(ProfileManagerBrowserTest, SwitchToProfile);
 
   // This struct contains information about profiles which are being loaded or
   // were loaded.
diff --git a/chrome/browser/profiles/profile_manager_browsertest.cc b/chrome/browser/profiles/profile_manager_browsertest.cc
index 7b96cc4..5243d66 100644
--- a/chrome/browser/profiles/profile_manager_browsertest.cc
+++ b/chrome/browser/profiles/profile_manager_browsertest.cc
@@ -8,6 +8,8 @@
 #include "chrome/browser/profiles/profile_info_cache.h"
 #include "chrome/browser/profiles/profile_info_cache_observer.h"
 #include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/profiles/profile_window.h"
+#include "chrome/browser/profiles/profiles_state.h"
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/host_desktop.h"
@@ -181,3 +183,55 @@
     BrowserList::CloseAllBrowsersWithProfile(*it);
   }
 }
+
+IN_PROC_BROWSER_TEST_F(ProfileManagerBrowserTest,
+                       SwitchToProfile) {
+  // If multiprofile mode is not enabled, you can't switch between profiles.
+  if (!profiles::IsMultipleProfilesEnabled())
+    return;
+
+
+  ProfileManager* profile_manager = g_browser_process->profile_manager();
+  ProfileInfoCache& cache = profile_manager->GetProfileInfoCache();
+  base::FilePath path_profile1 = cache.GetPathOfProfileAtIndex(0);
+
+  ASSERT_EQ(profile_manager->GetNumberOfProfiles(), 1U);
+  EXPECT_EQ(chrome::GetTotalBrowserCount(), 1U);
+
+  // Create an additional profile.
+  base::FilePath path_profile2 =
+      profile_manager->GenerateNextProfileDirectoryPath();
+  profile_manager->CreateProfileAsync(path_profile2,
+                                      base::Bind(&OnUnblockOnProfileCreation),
+                                      string16(), string16(), false);
+
+  // Spin to allow profile creation to take place, loop is terminated
+  // by OnUnblockOnProfileCreation when the profile is created.
+  content::RunMessageLoop();
+
+  chrome::HostDesktopType desktop_type = chrome::HOST_DESKTOP_TYPE_NATIVE;
+  BrowserList* browser_list = BrowserList::GetInstance(desktop_type);
+  ASSERT_EQ(cache.GetNumberOfProfiles(), 2U);
+  EXPECT_EQ(1U, browser_list->size());
+
+  // Open a browser window for the first profile.
+  profiles::SwitchToProfile(path_profile1, desktop_type, false);
+  EXPECT_EQ(chrome::GetTotalBrowserCount(), 1U);
+  EXPECT_EQ(1U, browser_list->size());
+  EXPECT_EQ(path_profile1, browser_list->get(0)->profile()->GetPath());
+
+  // Open a browser window for the second profile.
+  profiles::SwitchToProfile(path_profile2, desktop_type, false);
+  EXPECT_EQ(chrome::GetTotalBrowserCount(), 2U);
+  EXPECT_EQ(2U, browser_list->size());
+  EXPECT_EQ(path_profile2, browser_list->get(1)->profile()->GetPath());
+
+  // Switch to the first profile without opening a new window.
+  profiles::SwitchToProfile(path_profile1, desktop_type, false);
+  EXPECT_EQ(chrome::GetTotalBrowserCount(), 2U);
+  EXPECT_EQ(2U, browser_list->size());
+
+  EXPECT_EQ(path_profile1, browser_list->get(0)->profile()->GetPath());
+  EXPECT_EQ(path_profile2, browser_list->get(1)->profile()->GetPath());
+
+}
diff --git a/chrome/browser/profiles/profile_shortcut_manager.h b/chrome/browser/profiles/profile_shortcut_manager.h
index 9091ad6..602757d 100644
--- a/chrome/browser/profiles/profile_shortcut_manager.h
+++ b/chrome/browser/profiles/profile_shortcut_manager.h
@@ -16,6 +16,12 @@
  public:
   virtual ~ProfileShortcutManager();
 
+  // Create a profile icon for the profile with path |profile_path|.
+  // |callback| is called only on creation success.
+  virtual void CreateOrUpdateProfileIcon(
+      const base::FilePath& profile_path,
+      const base::Closure& callback) = 0;
+
   // Create a profile shortcut for the profile with path |profile_path|, plus
   // update the original profile shortcut if |profile_path| is the second
   // profile created.
diff --git a/chrome/browser/profiles/profile_shortcut_manager_unittest_win.cc b/chrome/browser/profiles/profile_shortcut_manager_unittest_win.cc
index 5e3cf5f..4afb347 100644
--- a/chrome/browser/profiles/profile_shortcut_manager_unittest_win.cc
+++ b/chrome/browser/profiles/profile_shortcut_manager_unittest_win.cc
@@ -71,16 +71,17 @@
       profile_info_cache_->DeleteProfileFromCache(profile_path);
       RunPendingTasks();
       ASSERT_FALSE(ProfileShortcutExistsAtDefaultPath(profile_name));
+      // The icon file is not deleted until the profile directory is deleted.
       const base::FilePath icon_path =
-          profile_path.AppendASCII(profiles::internal::kProfileIconFileName);
-      ASSERT_FALSE(base::PathExists(icon_path));
+          profiles::internal::GetProfileIconPath(profile_path);
+      ASSERT_TRUE(base::PathExists(icon_path));
     }
   }
 
   base::FilePath CreateProfileDirectory(const string16& profile_name) {
     const base::FilePath profile_path =
         profile_info_cache_->GetUserDataDir().Append(profile_name);
-    file_util::CreateDirectoryW(profile_path);
+    file_util::CreateDirectory(profile_path);
     return profile_path;
   }
 
@@ -134,7 +135,7 @@
 
     // Ensure that the corresponding icon exists.
     const base::FilePath icon_path =
-        profile_path.AppendASCII(profiles::internal::kProfileIconFileName);
+        profiles::internal::GetProfileIconPath(profile_path);
     EXPECT_TRUE(base::PathExists(icon_path)) << location.ToString();
 
     base::win::ShortcutProperties expected_properties;
@@ -760,7 +761,7 @@
       CreateRegularSystemLevelShortcut(FROM_HERE);
 
   // Delete the profile that has a shortcut, which will exercise the non-profile
-  // shortcut creation path in |DeleteDesktopShortcutsAndIconFile()|, which is
+  // shortcut creation path in |DeleteDesktopShortcuts()|, which is
   // not covered by the |DeleteSecondToLastProfileWithSystemLevelShortcut| test.
   profile_info_cache_->DeleteProfileFromCache(profile_2_path_);
   RunPendingTasks();
@@ -772,3 +773,95 @@
   EXPECT_FALSE(base::PathExists(profile_1_shortcut_path));
   EXPECT_FALSE(base::PathExists(profile_2_shortcut_path));
 }
+
+TEST_F(ProfileShortcutManagerTest, CreateProfileIcon) {
+  SetupDefaultProfileShortcut(FROM_HERE);
+
+  const base::FilePath icon_path =
+      profiles::internal::GetProfileIconPath(profile_1_path_);
+
+  EXPECT_TRUE(base::PathExists(icon_path));
+  EXPECT_TRUE(base::DeleteFile(icon_path, false));
+  EXPECT_FALSE(base::PathExists(icon_path));
+
+  profile_shortcut_manager_->CreateOrUpdateProfileIcon(profile_1_path_,
+                                                       base::Closure());
+  RunPendingTasks();
+  EXPECT_TRUE(base::PathExists(icon_path));
+}
+
+TEST_F(ProfileShortcutManagerTest, UnbadgeProfileIconOnDeletion) {
+  SetupDefaultProfileShortcut(FROM_HERE);
+  const base::FilePath icon_path_1 =
+      profiles::internal::GetProfileIconPath(profile_1_path_);
+  const base::FilePath icon_path_2 =
+      profiles::internal::GetProfileIconPath(profile_2_path_);
+
+  // Default profile has unbadged icon to start.
+  std::string unbadged_icon_1;
+  EXPECT_TRUE(file_util::ReadFileToString(icon_path_1, &unbadged_icon_1));
+
+  // Creating a new profile adds a badge to both the new profile icon and the
+  // default profile icon. Since they use the same icon index, the icon files
+  // should be the same.
+  CreateProfileWithShortcut(FROM_HERE, profile_2_name_, profile_2_path_);
+
+  std::string badged_icon_1;
+  EXPECT_TRUE(file_util::ReadFileToString(icon_path_1, &badged_icon_1));
+  std::string badged_icon_2;
+  EXPECT_TRUE(file_util::ReadFileToString(icon_path_2, &badged_icon_2));
+
+  EXPECT_NE(badged_icon_1, unbadged_icon_1);
+  EXPECT_EQ(badged_icon_1, badged_icon_2);
+
+  // Deleting the default profile will unbadge the new profile's icon and should
+  // result in an icon that is identical to the unbadged default profile icon.
+  profile_info_cache_->DeleteProfileFromCache(profile_1_path_);
+  RunPendingTasks();
+
+  std::string unbadged_icon_2;
+  EXPECT_TRUE(file_util::ReadFileToString(icon_path_2, &unbadged_icon_2));
+  EXPECT_EQ(unbadged_icon_1, unbadged_icon_2);
+}
+
+TEST_F(ProfileShortcutManagerTest, ProfileIconOnAvatarChange) {
+  SetupAndCreateTwoShortcuts(FROM_HERE);
+  const base::FilePath icon_path_1 =
+      profiles::internal::GetProfileIconPath(profile_1_path_);
+  const base::FilePath icon_path_2 =
+      profiles::internal::GetProfileIconPath(profile_2_path_);
+  const size_t profile_index_1 =
+      profile_info_cache_->GetIndexOfProfileWithPath(profile_1_path_);
+
+  std::string badged_icon_1;
+  EXPECT_TRUE(file_util::ReadFileToString(icon_path_1, &badged_icon_1));
+  std::string badged_icon_2;
+  EXPECT_TRUE(file_util::ReadFileToString(icon_path_2, &badged_icon_2));
+
+  // Profile 1 and 2 are created with the same icon.
+  EXPECT_EQ(badged_icon_1, badged_icon_2);
+
+  // Change profile 1's icon.
+  profile_info_cache_->SetAvatarIconOfProfileAtIndex(profile_index_1, 1);
+  RunPendingTasks();
+
+  std::string new_badged_icon_1;
+  EXPECT_TRUE(file_util::ReadFileToString(icon_path_1, &new_badged_icon_1));
+  EXPECT_NE(new_badged_icon_1, badged_icon_1);
+
+  // Ensure the new icon is not the unbadged icon.
+  profile_info_cache_->DeleteProfileFromCache(profile_2_path_);
+  RunPendingTasks();
+
+  std::string unbadged_icon_1;
+  EXPECT_TRUE(file_util::ReadFileToString(icon_path_1, &unbadged_icon_1));
+  EXPECT_NE(unbadged_icon_1, new_badged_icon_1);
+
+  // Ensure the icon doesn't change on avatar change without 2 profiles.
+  profile_info_cache_->SetAvatarIconOfProfileAtIndex(profile_index_1, 1);
+  RunPendingTasks();
+
+  std::string unbadged_icon_1_a;
+  EXPECT_TRUE(file_util::ReadFileToString(icon_path_1, &unbadged_icon_1_a));
+  EXPECT_EQ(unbadged_icon_1, unbadged_icon_1_a);
+}
diff --git a/chrome/browser/profiles/profile_shortcut_manager_win.cc b/chrome/browser/profiles/profile_shortcut_manager_win.cc
index cc8c250..7ce8ca2 100644
--- a/chrome/browser/profiles/profile_shortcut_manager_win.cc
+++ b/chrome/browser/profiles/profile_shortcut_manager_win.cc
@@ -14,6 +14,7 @@
 #include "base/file_util.h"
 #include "base/files/file_enumerator.h"
 #include "base/path_service.h"
+#include "base/prefs/pref_service.h"
 #include "base/strings/string16.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
@@ -21,15 +22,18 @@
 #include "base/win/shortcut.h"
 #include "chrome/browser/app_icon_win.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/profiles/profile_info_cache_observer.h"
 #include "chrome/browser/profiles/profile_info_util.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/shell_integration.h"
 #include "chrome/common/chrome_switches.h"
+#include "chrome/common/pref_names.h"
 #include "chrome/installer/util/browser_distribution.h"
 #include "chrome/installer/util/product.h"
 #include "chrome/installer/util/shell_util.h"
 #include "content/public/browser/browser_thread.h"
+#include "content/public/browser/notification_service.h"
 #include "grit/chrome_unscaled_resources.h"
 #include "grit/chromium_strings.h"
 #include "skia/ext/image_operations.h"
@@ -46,6 +50,9 @@
 
 namespace {
 
+// Name of the badged icon file generated for a given profile.
+const char kProfileIconFileName[] = "Google Profile.ico";
+
 // Characters that are not allowed in Windows filenames. Taken from
 // http://msdn.microsoft.com/en-us/library/aa365247.aspx
 const char16 kReservedCharacters[] = L"<>:\"/\\|?*\x01\x02\x03\x04\x05\x06\x07"
@@ -61,6 +68,8 @@
 const int kProfileAvatarBadgeSize = 28;
 const int kShortcutIconSize = 48;
 
+const int kCurrentProfileIconVersion = 1;
+
 // 2x sized profile avatar icons. Mirrors |kDefaultAvatarIconResources| in
 // profile_info_cache.cc.
 const int kProfileAvatarIconResources2x[] = {
@@ -141,35 +150,92 @@
 // Creates a desktop shortcut icon file (.ico) on the disk for a given profile,
 // badging the browser distribution icon with the profile avatar.
 // Returns a path to the shortcut icon file on disk, which is empty if this
-// fails. Use index 0 when assigning the resulting file as the icon.
-base::FilePath CreateChromeDesktopShortcutIconForProfile(
+// fails. Use index 0 when assigning the resulting file as the icon. If both
+// given bitmaps are empty, an unbadged icon is created.
+// |callback| will be run on successful icon creation.
+// Returns the path to the created icon on success and an empty base::FilePath
+// on failure.
+// TODO(calamity): Ideally we'd just copy the app icon verbatim from the exe's
+// resources in the case of an unbadged icon.
+base::FilePath CreateOrUpdateShortcutIconForProfile(
     const base::FilePath& profile_path,
     const SkBitmap& avatar_bitmap_1x,
-    const SkBitmap& avatar_bitmap_2x) {
+    const SkBitmap& avatar_bitmap_2x,
+    const base::Closure& callback) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+
+  if (!base::PathExists(profile_path)) {
+    LOG(ERROR) << "Profile directory " << profile_path.value()
+               << " did not exist when trying to create profile icon";
+    return base::FilePath();
+  }
+
   scoped_ptr<SkBitmap> app_icon_bitmap(GetAppIconForSize(kShortcutIconSize));
   if (!app_icon_bitmap)
     return base::FilePath();
 
   gfx::ImageFamily badged_bitmaps;
-  badged_bitmaps.Add(gfx::Image::CreateFrom1xBitmap(
-      BadgeIcon(*app_icon_bitmap, avatar_bitmap_1x, 1)));
-
-  app_icon_bitmap = GetAppIconForSize(IconUtil::kLargeIconSize);
-  if (app_icon_bitmap) {
+  if (!avatar_bitmap_1x.empty()) {
     badged_bitmaps.Add(gfx::Image::CreateFrom1xBitmap(
-        BadgeIcon(*app_icon_bitmap, avatar_bitmap_2x, 2)));
+        BadgeIcon(*app_icon_bitmap, avatar_bitmap_1x, 1)));
   }
 
+  scoped_ptr<SkBitmap> large_app_icon_bitmap(
+      GetAppIconForSize(IconUtil::kLargeIconSize));
+  if (large_app_icon_bitmap && !avatar_bitmap_2x.empty()) {
+    badged_bitmaps.Add(gfx::Image::CreateFrom1xBitmap(
+        BadgeIcon(*large_app_icon_bitmap, avatar_bitmap_2x, 2)));
+  }
+
+  // If we have no badged bitmaps, we should just use the default chrome icon.
+  if (badged_bitmaps.empty()) {
+    badged_bitmaps.Add(gfx::Image::CreateFrom1xBitmap(*app_icon_bitmap));
+    if (large_app_icon_bitmap) {
+      badged_bitmaps.Add(
+          gfx::Image::CreateFrom1xBitmap(*large_app_icon_bitmap));
+    }
+  }
   // Finally, write the .ico file containing this new bitmap.
   const base::FilePath icon_path =
-      profile_path.AppendASCII(profiles::internal::kProfileIconFileName);
-  if (!IconUtil::CreateIconFileFromImageFamily(badged_bitmaps, icon_path))
-    return base::FilePath();
+      profiles::internal::GetProfileIconPath(profile_path);
+  const bool had_icon = base::PathExists(icon_path);
 
+  if (!IconUtil::CreateIconFileFromImageFamily(badged_bitmaps, icon_path)) {
+    // This can happen in theory if the profile directory is deleted between the
+    // beginning of this function and here; however this is extremely unlikely
+    // and this check will help catch any regression where this call would start
+    // failing constantly.
+    NOTREACHED();
+    return base::FilePath();
+  }
+
+  if (had_icon) {
+    // This invalidates the Windows icon cache and causes the icon changes to
+    // register with the taskbar and desktop. SHCNE_ASSOCCHANGED will cause a
+    // desktop flash and we would like to avoid that if possible.
+    SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL);
+  } else {
+    SHChangeNotify(SHCNE_CREATE, SHCNF_PATH, icon_path.value().c_str(), NULL);
+  }
+  if (!callback.is_null())
+    BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback);
   return icon_path;
 }
 
+// Updates the preferences with the current icon version on icon creation
+// success.
+void OnProfileIconCreateSuccess(base::FilePath profile_path) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  if (!g_browser_process->profile_manager())
+    return;
+  Profile* profile =
+      g_browser_process->profile_manager()->GetProfileByPath(profile_path);
+  if (profile) {
+    profile->GetPrefs()->SetInteger(prefs::kProfileIconVersion,
+                                    kCurrentProfileIconVersion);
+  }
+}
+
 // Gets the user and system directories for desktop shortcuts. Parameters may
 // be NULL if a directory type is not needed. Returns true on success.
 bool GetDesktopShortcutsDirectories(
@@ -301,7 +367,8 @@
     // It's also possible that a system-level shortcut exists instead - this
     // should only be the case for the original Chrome shortcut from an
     // installation. If that's the case, copy that one over - it will get its
-    // properties updated by |CreateOrUpdateDesktopShortcutsForProfile()|.
+    // properties updated by
+    // |CreateOrUpdateDesktopShortcutsAndIconForProfile()|.
     const base::FilePath possible_old_system_shortcut =
         system_shortcuts_directory.Append(old_shortcut_filename);
     if (base::PathExists(possible_old_system_shortcut))
@@ -309,20 +376,49 @@
   }
 }
 
+struct CreateOrUpdateShortcutsParams {
+  CreateOrUpdateShortcutsParams(
+      base::FilePath profile_path,
+      ProfileShortcutManagerWin::CreateOrUpdateMode create_mode,
+      ProfileShortcutManagerWin::NonProfileShortcutAction action)
+      : profile_path(profile_path), create_mode(create_mode), action(action) {}
+  ~CreateOrUpdateShortcutsParams() {}
+
+  ProfileShortcutManagerWin::CreateOrUpdateMode create_mode;
+  ProfileShortcutManagerWin::NonProfileShortcutAction action;
+
+  // The path for this profile.
+  base::FilePath profile_path;
+  // The profile name before this update. Empty on create.
+  string16 old_profile_name;
+  // The new profile name.
+  string16 profile_name;
+  // Avatar images for this profile.
+  SkBitmap avatar_image_1x;
+  SkBitmap avatar_image_2x;
+};
+
 // Updates all desktop shortcuts for the given profile to have the specified
-// parameters. If |create_mode| is CREATE_WHEN_NONE_FOUND, a new shortcut is
-// created if no existing ones were found. Whether non-profile shortcuts should
-// be updated is specified by |action|. Must be called on the FILE thread.
-void CreateOrUpdateDesktopShortcutsForProfile(
-    const base::FilePath& profile_path,
-    const string16& old_profile_name,
-    const string16& profile_name,
-    const SkBitmap& avatar_image_1x,
-    const SkBitmap& avatar_image_2x,
-    ProfileShortcutManagerWin::CreateOrUpdateMode create_mode,
-    ProfileShortcutManagerWin::NonProfileShortcutAction action) {
+// parameters. If |params.create_mode| is CREATE_WHEN_NONE_FOUND, a new shortcut
+// is created if no existing ones were found. Whether non-profile shortcuts
+// should be updated is specified by |params.action|. Must be called on the FILE
+// thread. |callback| is called on successful icon creation.
+void CreateOrUpdateDesktopShortcutsAndIconForProfile(
+    const CreateOrUpdateShortcutsParams& params,
+    const base::Closure& callback) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
 
+  const base::FilePath shortcut_icon =
+      CreateOrUpdateShortcutIconForProfile(params.profile_path,
+                                           params.avatar_image_1x,
+                                           params.avatar_image_2x,
+                                           callback);
+  if (shortcut_icon.empty() ||
+      params.create_mode ==
+          ProfileShortcutManagerWin::CREATE_OR_UPDATE_ICON_ONLY) {
+    return;
+  }
+
   base::FilePath chrome_exe;
   if (!PathService::Get(base::FILE_EXE, &chrome_exe)) {
     NOTREACHED();
@@ -334,12 +430,13 @@
   // the following code may result in NOTREACHED() being hit.
   DCHECK(distribution->CanCreateDesktopShortcuts());
 
-  if (old_profile_name != profile_name) {
+  if (params.old_profile_name != params.profile_name) {
     const string16 old_shortcut_filename =
-        profiles::internal::GetShortcutFilenameForProfile(old_profile_name,
-                                                          distribution);
+        profiles::internal::GetShortcutFilenameForProfile(
+            params.old_profile_name,
+            distribution);
     const string16 new_shortcut_filename =
-        profiles::internal::GetShortcutFilenameForProfile(profile_name,
+        profiles::internal::GetShortcutFilenameForProfile(params.profile_name,
                                                           distribution);
     RenameChromeDesktopShortcutForProfile(old_shortcut_filename,
                                           new_shortcut_filename);
@@ -350,19 +447,14 @@
   product.AddDefaultShortcutProperties(chrome_exe, &properties);
 
   const string16 command_line =
-      profiles::internal::CreateProfileShortcutFlags(profile_path);
+      profiles::internal::CreateProfileShortcutFlags(params.profile_path);
 
   // Only set the profile-specific properties when |profile_name| is non empty.
   // If it is empty, it means the shortcut being created should be a regular,
   // non-profile Chrome shortcut.
-  if (!profile_name.empty()) {
-    const base::FilePath shortcut_icon =
-        CreateChromeDesktopShortcutIconForProfile(profile_path,
-                                                  avatar_image_1x,
-                                                  avatar_image_2x);
-    if (!shortcut_icon.empty())
-      properties.set_icon(shortcut_icon, 0);
+  if (!params.profile_name.empty()) {
     properties.set_arguments(command_line);
+    properties.set_icon(shortcut_icon, 0);
   } else {
     // Set the arguments explicitly to the empty string to ensure that
     // |ShellUtil::CreateOrUpdateShortcut| updates that part of the shortcut.
@@ -370,19 +462,19 @@
   }
 
   properties.set_app_id(
-      ShellIntegration::GetChromiumModelIdForProfile(profile_path));
+      ShellIntegration::GetChromiumModelIdForProfile(params.profile_path));
 
   ShellUtil::ShortcutOperation operation =
       ShellUtil::SHELL_SHORTCUT_REPLACE_EXISTING;
 
   std::vector<base::FilePath> shortcuts;
   ListDesktopShortcutsWithCommandLine(chrome_exe, command_line,
-      action == ProfileShortcutManagerWin::UPDATE_NON_PROFILE_SHORTCUTS,
+      params.action == ProfileShortcutManagerWin::UPDATE_NON_PROFILE_SHORTCUTS,
       &shortcuts);
-  if (create_mode == ProfileShortcutManagerWin::CREATE_WHEN_NONE_FOUND &&
+  if (params.create_mode == ProfileShortcutManagerWin::CREATE_WHEN_NONE_FOUND &&
       shortcuts.empty()) {
     const string16 shortcut_name =
-        profiles::internal::GetShortcutFilenameForProfile(profile_name,
+        profiles::internal::GetShortcutFilenameForProfile(params.profile_name,
                                                           distribution);
     shortcuts.push_back(base::FilePath(shortcut_name));
     operation = ShellUtil::SHELL_SHORTCUT_CREATE_IF_NO_SYSTEM_LEVEL;
@@ -415,12 +507,12 @@
   return false;
 }
 
-// Deletes all desktop shortcuts for the specified profile and also removes the
-// corresponding icon file. If |ensure_shortcuts_remain| is true, then a regular
-// non-profile shortcut will be created if this function would otherwise delete
-// the last Chrome desktop shortcut(s). Must be called on the FILE thread.
-void DeleteDesktopShortcutsAndIconFile(const base::FilePath& profile_path,
-                                       bool ensure_shortcuts_remain) {
+// Deletes all desktop shortcuts for the specified profile. If
+// |ensure_shortcuts_remain| is true, then a regular non-profile shortcut will
+// be created if this function would otherwise delete the last Chrome desktop
+// shortcut(s). Must be called on the FILE thread.
+void DeleteDesktopShortcuts(const base::FilePath& profile_path,
+                            bool ensure_shortcuts_remain) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
 
   base::FilePath chrome_exe;
@@ -445,10 +537,6 @@
                    NULL);
   }
 
-  const base::FilePath icon_path =
-      profile_path.AppendASCII(profiles::internal::kProfileIconFileName);
-  base::DeleteFile(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.
   const bool had_shortcuts = !shortcuts.empty();
@@ -530,7 +618,9 @@
 namespace profiles {
 namespace internal {
 
-const char kProfileIconFileName[] = "Google Profile.ico";
+base::FilePath GetProfileIconPath(const base::FilePath& profile_path) {
+  return profile_path.AppendASCII(kProfileIconFileName);
+}
 
 string16 GetShortcutFilenameForProfile(const string16& profile_name,
                                        BrowserDistribution* distribution) {
@@ -572,6 +662,9 @@
       arraysize(kProfileAvatarIconResources2x),
       profile_manager_->GetProfileInfoCache().GetDefaultAvatarIconCount());
 
+  registrar_.Add(this, chrome::NOTIFICATION_PROFILE_CREATED,
+                 content::NotificationService::AllSources());
+
   profile_manager_->GetProfileInfoCache().AddObserver(this);
 }
 
@@ -579,17 +672,27 @@
   profile_manager_->GetProfileInfoCache().RemoveObserver(this);
 }
 
+void ProfileShortcutManagerWin::CreateOrUpdateProfileIcon(
+    const base::FilePath& profile_path,
+    const base::Closure& callback) {
+  CreateOrUpdateShortcutsForProfileAtPath(profile_path,
+                                          CREATE_OR_UPDATE_ICON_ONLY,
+                                          IGNORE_NON_PROFILE_SHORTCUTS,
+                                          callback);
+}
+
 void ProfileShortcutManagerWin::CreateProfileShortcut(
     const base::FilePath& profile_path) {
   CreateOrUpdateShortcutsForProfileAtPath(profile_path, CREATE_WHEN_NONE_FOUND,
-                                          IGNORE_NON_PROFILE_SHORTCUTS);
+                                          IGNORE_NON_PROFILE_SHORTCUTS,
+                                          base::Closure());
 }
 
 void ProfileShortcutManagerWin::RemoveProfileShortcuts(
     const base::FilePath& profile_path) {
   BrowserThread::PostTask(
       BrowserThread::FILE, FROM_HERE,
-      base::Bind(&DeleteDesktopShortcutsAndIconFile, profile_path, false));
+      base::Bind(&DeleteDesktopShortcuts, profile_path, false));
 }
 
 void ProfileShortcutManagerWin::HasProfileShortcuts(
@@ -602,12 +705,14 @@
 
 void ProfileShortcutManagerWin::OnProfileAdded(
     const base::FilePath& profile_path) {
+  CreateOrUpdateProfileIcon(profile_path, base::Closure());
   if (profile_manager_->GetProfileInfoCache().GetNumberOfProfiles() == 2) {
     // When the second profile is added, make existing non-profile shortcuts
     // point to the first profile and be badged/named appropriately.
     CreateOrUpdateShortcutsForProfileAtPath(GetOtherProfilePath(profile_path),
                                             UPDATE_EXISTING_ONLY,
-                                            UPDATE_NON_PROFILE_SHORTCUTS);
+                                            UPDATE_NON_PROFILE_SHORTCUTS,
+                                            base::Closure());
   }
 }
 
@@ -619,13 +724,15 @@
   // from an existing shortcut.
   const bool deleting_down_to_last_profile = (cache.GetNumberOfProfiles() == 1);
   if (deleting_down_to_last_profile) {
+    // This is needed to unbadge the icon.
     CreateOrUpdateShortcutsForProfileAtPath(cache.GetPathOfProfileAtIndex(0),
                                             UPDATE_EXISTING_ONLY,
-                                            IGNORE_NON_PROFILE_SHORTCUTS);
+                                            IGNORE_NON_PROFILE_SHORTCUTS,
+                                            base::Closure());
   }
 
   BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
-                          base::Bind(&DeleteDesktopShortcutsAndIconFile,
+                          base::Bind(&DeleteDesktopShortcuts,
                                      profile_path,
                                      deleting_down_to_last_profile));
 }
@@ -634,13 +741,13 @@
     const base::FilePath& profile_path,
     const string16& old_profile_name) {
   CreateOrUpdateShortcutsForProfileAtPath(profile_path, UPDATE_EXISTING_ONLY,
-                                          IGNORE_NON_PROFILE_SHORTCUTS);
+                                          IGNORE_NON_PROFILE_SHORTCUTS,
+                                          base::Closure());
 }
 
 void ProfileShortcutManagerWin::OnProfileAvatarChanged(
     const base::FilePath& profile_path) {
-  CreateOrUpdateShortcutsForProfileAtPath(profile_path, UPDATE_EXISTING_ONLY,
-                                          IGNORE_NON_PROFILE_SHORTCUTS);
+  CreateOrUpdateProfileIcon(profile_path, base::Closure());
 }
 
 base::FilePath ProfileShortcutManagerWin::GetOtherProfilePath(
@@ -657,32 +764,33 @@
 void ProfileShortcutManagerWin::CreateOrUpdateShortcutsForProfileAtPath(
     const base::FilePath& profile_path,
     CreateOrUpdateMode create_mode,
-    NonProfileShortcutAction action) {
+    NonProfileShortcutAction action,
+    const base::Closure& callback) {
+  DCHECK(!BrowserThread::IsWellKnownThread(BrowserThread::UI) ||
+      BrowserThread::CurrentlyOn(BrowserThread::UI));
+  CreateOrUpdateShortcutsParams params(profile_path, create_mode, action);
+
   ProfileInfoCache* cache = &profile_manager_->GetProfileInfoCache();
   size_t profile_index = cache->GetIndexOfProfileWithPath(profile_path);
   if (profile_index == std::string::npos)
     return;
   bool remove_badging = cache->GetNumberOfProfiles() == 1;
 
-  string16 old_shortcut_appended_name =
+  params.old_profile_name =
       cache->GetShortcutNameOfProfileAtIndex(profile_index);
 
   // Exit early if the mode is to update existing profile shortcuts only and
   // none were ever created for this profile, per the shortcut name not being
   // set in the profile info cache.
-  if (old_shortcut_appended_name.empty() &&
+  if (params.old_profile_name.empty() &&
       create_mode == UPDATE_EXISTING_ONLY &&
       action == IGNORE_NON_PROFILE_SHORTCUTS) {
     return;
   }
 
-  string16 new_shortcut_appended_name;
-  if (!remove_badging)
-    new_shortcut_appended_name = cache->GetNameOfProfileAtIndex(profile_index);
-
-  SkBitmap avatar_bitmap_copy_1x;
-  SkBitmap avatar_bitmap_copy_2x;
   if (!remove_badging) {
+    params.profile_name = cache->GetNameOfProfileAtIndex(profile_index);
+
     const size_t icon_index =
         cache->GetAvatarIconIndexOfProfileAtIndex(profile_index);
     const int resource_id_1x =
@@ -690,16 +798,38 @@
     const int resource_id_2x = kProfileAvatarIconResources2x[icon_index];
     // Make a copy of the SkBitmaps to ensure that we can safely use the image
     // data on the FILE thread.
-    avatar_bitmap_copy_1x = GetImageResourceSkBitmapCopy(resource_id_1x);
-    avatar_bitmap_copy_2x = GetImageResourceSkBitmapCopy(resource_id_2x);
+    params.avatar_image_1x = GetImageResourceSkBitmapCopy(resource_id_1x);
+    params.avatar_image_2x = GetImageResourceSkBitmapCopy(resource_id_2x);
   }
   BrowserThread::PostTask(
       BrowserThread::FILE, FROM_HERE,
-      base::Bind(&CreateOrUpdateDesktopShortcutsForProfile, profile_path,
-                 old_shortcut_appended_name, new_shortcut_appended_name,
-                 avatar_bitmap_copy_1x, avatar_bitmap_copy_2x, create_mode,
-                 action));
+      base::Bind(&CreateOrUpdateDesktopShortcutsAndIconForProfile, params,
+                 callback));
 
   cache->SetShortcutNameOfProfileAtIndex(profile_index,
-                                         new_shortcut_appended_name);
+                                         params.profile_name);
+}
+
+void ProfileShortcutManagerWin::Observe(
+    int type,
+    const content::NotificationSource& source,
+    const content::NotificationDetails& details) {
+  switch (type) {
+    // This notification is triggered when a profile is loaded.
+    case chrome::NOTIFICATION_PROFILE_CREATED: {
+      Profile* profile =
+          content::Source<Profile>(source).ptr()->GetOriginalProfile();
+      if (profile->GetPrefs()->GetInteger(prefs::kProfileIconVersion) <
+          kCurrentProfileIconVersion) {
+        // Ensure the profile's icon file has been created.
+        CreateOrUpdateProfileIcon(
+            profile->GetPath(),
+            base::Bind(&OnProfileIconCreateSuccess, profile->GetPath()));
+      }
+      break;
+    }
+    default:
+      NOTREACHED();
+      break;
+  }
 }
diff --git a/chrome/browser/profiles/profile_shortcut_manager_win.h b/chrome/browser/profiles/profile_shortcut_manager_win.h
index fa627a4..4ecbfec 100644
--- a/chrome/browser/profiles/profile_shortcut_manager_win.h
+++ b/chrome/browser/profiles/profile_shortcut_manager_win.h
@@ -5,7 +5,10 @@
 #ifndef CHROME_BROWSER_PROFILES_PROFILE_SHORTCUT_MANAGER_WIN_H_
 #define CHROME_BROWSER_PROFILES_PROFILE_SHORTCUT_MANAGER_WIN_H_
 
+#include "base/callback.h"
 #include "chrome/browser/profiles/profile_shortcut_manager.h"
+#include "content/public/browser/notification_observer.h"
+#include "content/public/browser/notification_registrar.h"
 
 class BrowserDistribution;
 
@@ -13,8 +16,8 @@
 namespace profiles {
 namespace internal {
 
-// Name of the badged icon file generated for a given profile.
-extern const char kProfileIconFileName[];
+// Returns the full path to the profile icon file.
+base::FilePath GetProfileIconPath(const base::FilePath& profile_path);
 
 // Returns the default shortcut filename for the given profile name,
 // given |distribution|. Returns a filename appropriate for a
@@ -29,12 +32,16 @@
 }  // namespace profiles
 
 class ProfileShortcutManagerWin : public ProfileShortcutManager,
-                                  public ProfileInfoCacheObserver {
+                                  public ProfileInfoCacheObserver,
+                                  public content::NotificationObserver {
  public:
-  // Specifies whether a new shortcut should be created if none exist.
+  // Specifies whether only the existing shortcut should be updated, a new
+  // shortcut should be created if none exist, or only the icon for this profile
+  // should be created in the profile directory.
   enum CreateOrUpdateMode {
     UPDATE_EXISTING_ONLY,
     CREATE_WHEN_NONE_FOUND,
+    CREATE_OR_UPDATE_ICON_ONLY,
   };
   // Specifies whether non-profile shortcuts should be updated.
   enum NonProfileShortcutAction {
@@ -46,6 +53,9 @@
   virtual ~ProfileShortcutManagerWin();
 
   // ProfileShortcutManager implementation:
+  virtual void CreateOrUpdateProfileIcon(
+      const base::FilePath& profile_path,
+      const base::Closure& callback) OVERRIDE;
   virtual void CreateProfileShortcut(
       const base::FilePath& profile_path) OVERRIDE;
   virtual void RemoveProfileShortcuts(
@@ -63,18 +73,30 @@
   virtual void OnProfileAvatarChanged(
       const base::FilePath& profile_path) OVERRIDE;
 
+  // content::NotificationObserver implementation:
+  virtual void Observe(int type,
+                       const content::NotificationSource& source,
+                       const content::NotificationDetails& details) OVERRIDE;
+
  private:
   // Gives the profile path of an alternate profile than |profile_path|.
   // Must only be called when the number profiles is 2.
   base::FilePath GetOtherProfilePath(const base::FilePath& profile_path);
 
+  // Creates or updates shortcuts for the profile at |profile_path| according
+  // to the specified |create_mode| and |action|. This will always involve
+  // creating or updating the icon file for this profile.
+  // Calls |callback| on successful icon creation.
   void CreateOrUpdateShortcutsForProfileAtPath(
       const base::FilePath& profile_path,
       CreateOrUpdateMode create_mode,
-      NonProfileShortcutAction action);
+      NonProfileShortcutAction action,
+      const base::Closure& callback);
 
   ProfileManager* profile_manager_;
 
+  content::NotificationRegistrar registrar_;
+
   DISALLOW_COPY_AND_ASSIGN(ProfileShortcutManagerWin);
 };
 
diff --git a/chrome/browser/profiles/profile_window.cc b/chrome/browser/profiles/profile_window.cc
index fb3276f..5523087 100644
--- a/chrome/browser/profiles/profile_window.cc
+++ b/chrome/browser/profiles/profile_window.cc
@@ -6,8 +6,11 @@
 
 #include "base/command_line.h"
 #include "base/files/file_path.h"
+#include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/browser.h"
+#include "content/public/browser/browser_thread.h"
 #include "content/public/browser/user_metrics.h"
 
 #if !defined(OS_IOS)
@@ -16,8 +19,29 @@
 #include "chrome/browser/ui/startup/startup_browser_creator.h"
 #endif  // !defined (OS_IOS)
 
+using content::BrowserThread;
 using content::UserMetricsAction;
 
+namespace {
+
+void OpenBrowserWindowForProfile(bool always_create,
+                                 chrome::HostDesktopType desktop_type,
+                                 Profile* profile,
+                                 Profile::CreateStatus status) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+  if (status == Profile::CREATE_STATUS_INITIALIZED) {
+    profiles::FindOrCreateNewWindowForProfile(
+        profile,
+        chrome::startup::IS_NOT_PROCESS_STARTUP,
+        chrome::startup::IS_NOT_FIRST_RUN,
+        desktop_type,
+        always_create);
+  }
+}
+
+}  // namespace
+
 namespace profiles {
 
 void FindOrCreateNewWindowForProfile(
@@ -48,4 +72,18 @@
 #endif  // defined(OS_IOS)
 }
 
+void SwitchToProfile(
+    const base::FilePath& path,
+    chrome::HostDesktopType desktop_type,
+    bool always_create) {
+  g_browser_process->profile_manager()->CreateProfileAsync(
+      path,
+      base::Bind(&OpenBrowserWindowForProfile,
+                 always_create,
+                 desktop_type),
+      string16(),
+      string16(),
+      false);
+}
+
 }  // namespace profiles
diff --git a/chrome/browser/profiles/profile_window.h b/chrome/browser/profiles/profile_window.h
index bf98403..f66b776 100644
--- a/chrome/browser/profiles/profile_window.h
+++ b/chrome/browser/profiles/profile_window.h
@@ -9,6 +9,7 @@
 #include "chrome/browser/ui/startup/startup_types.h"
 
 class Profile;
+namespace base { class FilePath; }
 
 namespace profiles {
 
@@ -25,6 +26,14 @@
     chrome::HostDesktopType desktop_type,
     bool always_create);
 
+// Opens a Browser with the specified profile given by |path|.
+// If |always_create| is true then a new window is created
+// even if a window for that profile already exists.
+void SwitchToProfile(
+    const base::FilePath& path,
+    chrome::HostDesktopType desktop_type,
+    bool always_create);
+
 }  // namespace profiles
 
 #endif  // CHROME_BROWSER_PROFILES_PROFILE_WINDOW_H_
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 d31d01f..9e5c8eb 100644
--- a/chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate.cc
+++ b/chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate.cc
@@ -34,7 +34,6 @@
 #include "chrome/browser/ui/login/login_prompt.h"
 #include "chrome/browser/ui/sync/one_click_signin_helper.h"
 #include "chrome/common/extensions/mime_types_handler.h"
-#include "chrome/common/extensions/user_script.h"
 #include "chrome/common/render_messages.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/notification_service.h"
@@ -45,6 +44,7 @@
 #include "content/public/browser/stream_handle.h"
 #include "content/public/common/resource_response.h"
 #include "extensions/common/constants.h"
+#include "extensions/common/user_script.h"
 #include "net/base/load_flags.h"
 #include "net/base/load_timing_info.h"
 #include "net/http/http_response_headers.h"
diff --git a/chrome/browser/renderer_host/pepper/pepper_extensions_common_message_filter.cc b/chrome/browser/renderer_host/pepper/pepper_extensions_common_message_filter.cc
index a0d93e6..e766128 100644
--- a/chrome/browser/renderer_host/pepper/pepper_extensions_common_message_filter.cc
+++ b/chrome/browser/renderer_host/pepper/pepper_extensions_common_message_filter.cc
@@ -23,7 +23,6 @@
 #include "ppapi/host/dispatch_host_message.h"
 #include "ppapi/host/host_message_context.h"
 #include "ppapi/proxy/ppapi_messages.h"
-#include "third_party/WebKit/public/web/WebSecurityOrigin.h"
 
 namespace chrome {
 
@@ -164,8 +163,6 @@
     return;
   Profile* profile = profile_manager->GetProfile(profile_directory_);
 
-  source_origin_ = WebKit::WebSecurityOrigin::create(document_url_).toString();
-
   // It will be automatically destroyed when |view_host| goes away.
   dispatcher_owner_ = new DispatcherOwner(this, profile, view_host);
 }
@@ -187,7 +184,6 @@
 
   params->extension_id = document_url_.host();
   params->source_url = document_url_;
-  params->source_origin = source_origin_;
 
   // We don't need an ID to map a response to the corresponding request.
   params->request_id = 0;
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 832e859..b231123 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
@@ -105,8 +105,6 @@
   DispatcherOwner* dispatcher_owner_;
   bool dispatcher_owner_initialized_;
 
-  base::string16 source_origin_;
-
   DISALLOW_COPY_AND_ASSIGN(PepperExtensionsCommonMessageFilter);
 };
 
diff --git a/chrome/browser/renderer_host/plugin_info_message_filter_unittest.cc b/chrome/browser/renderer_host/plugin_info_message_filter_unittest.cc
index 030f659..cca278a 100644
--- a/chrome/browser/renderer_host/plugin_info_message_filter_unittest.cc
+++ b/chrome/browser/renderer_host/plugin_info_message_filter_unittest.cc
@@ -13,10 +13,13 @@
 #include "chrome/common/render_messages.h"
 #include "content/public/browser/plugin_service.h"
 #include "content/public/browser/plugin_service_filter.h"
+#include "content/public/browser/render_process_host.h"
 #include "content/public/test/test_browser_thread.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "webkit/plugins/npapi/mock_plugin_list.h"
+
+// Linux Aura doesn't support NPAPI.
+#if !(defined(OS_LINUX) && defined(USE_AURA))
 
 using content::PluginService;
 
@@ -32,7 +35,7 @@
                                  const void* context,
                                  const GURL& url,
                                  const GURL& policy_url,
-                                 webkit::WebPluginInfo* plugin) OVERRIDE;
+                                 content::WebPluginInfo* plugin) OVERRIDE;
 
   virtual bool CanLoadPlugin(int render_process_id,
                              const base::FilePath& path) OVERRIDE;
@@ -50,7 +53,7 @@
                                                 const void* context,
                                                 const GURL& url,
                                                 const GURL& policy_url,
-                                                webkit::WebPluginInfo* plugin) {
+                                                content::WebPluginInfo* plugin) {
   std::map<base::FilePath, bool>::iterator it =
       plugin_state_.find(plugin->path);
   if (it == plugin_state_.end()) {
@@ -76,31 +79,38 @@
   }
 
   virtual void SetUp() OVERRIDE {
-    webkit::WebPluginInfo foo_plugin(ASCIIToUTF16("Foo Plug-in"),
-                                     foo_plugin_path_,
-                                     ASCIIToUTF16("1"),
-                                     ASCIIToUTF16("The Foo plug-in."));
-    webkit::WebPluginMimeType mimeType;
-    mimeType.mime_type = "foo/bar";
-    foo_plugin.mime_types.push_back(mimeType);
-    plugin_list_.AddPluginToLoad(foo_plugin);
+    content::WebPluginInfo foo_plugin(ASCIIToUTF16("Foo Plug-in"),
+                                      foo_plugin_path_,
+                                      ASCIIToUTF16("1"),
+                                      ASCIIToUTF16("The Foo plug-in."));
+    content::WebPluginMimeType mime_type;
+    mime_type.mime_type = "foo/bar";
+    foo_plugin.mime_types.push_back(mime_type);
+    PluginService::GetInstance()->Init();
+    PluginService::GetInstance()->RegisterInternalPlugin(foo_plugin, false);
 
-    webkit::WebPluginInfo bar_plugin(ASCIIToUTF16("Bar Plug-in"),
-                                     bar_plugin_path_,
-                                     ASCIIToUTF16("1"),
-                                     ASCIIToUTF16("The Bar plug-in."));
-    mimeType.mime_type = "foo/bar";
-    bar_plugin.mime_types.push_back(mimeType);
-    plugin_list_.AddPluginToLoad(bar_plugin);
+    content::WebPluginInfo bar_plugin(ASCIIToUTF16("Bar Plug-in"),
+                                      bar_plugin_path_,
+                                      ASCIIToUTF16("1"),
+                                      ASCIIToUTF16("The Bar plug-in."));
+    mime_type.mime_type = "foo/bar";
+    bar_plugin.mime_types.push_back(mime_type);
+    PluginService::GetInstance()->RegisterInternalPlugin(bar_plugin, false);
 
-    PluginService::GetInstance()->SetPluginListForTesting(&plugin_list_);
     PluginService::GetInstance()->SetFilter(&filter_);
 
+#if !defined(OS_WIN)
+    // Can't go out of process in unit tests.
+    content::RenderProcessHost::SetRunRendererInProcess(true);
+#endif
     PluginService::GetInstance()->GetPlugins(
         base::Bind(&PluginInfoMessageFilterTest::PluginsLoaded,
                    base::Unretained(this)));
     base::RunLoop run_loop;
     run_loop.Run();
+#if !defined(OS_WIN)
+    content::RenderProcessHost::SetRunRendererInProcess(false);
+#endif
   }
 
  protected:
@@ -110,7 +120,7 @@
   PluginInfoMessageFilter::Context context_;
 
  private:
-  void PluginsLoaded(const std::vector<webkit::WebPluginInfo>& plugins) {
+  void PluginsLoaded(const std::vector<content::WebPluginInfo>& plugins) {
     base::MessageLoop::current()->Quit();
   }
 
@@ -119,7 +129,6 @@
   // a MockPluginList.
   content::TestBrowserThread file_thread_;
   base::ShadowingAtExitManager at_exit_manager_;  // Destroys the PluginService.
-  webkit::npapi::MockPluginList plugin_list_;
 };
 
 TEST_F(PluginInfoMessageFilterTest, FindEnabledPlugin) {
@@ -127,7 +136,7 @@
   filter_.set_plugin_enabled(bar_plugin_path_, true);
   {
     ChromeViewHostMsg_GetPluginInfo_Status status;
-    webkit::WebPluginInfo plugin;
+    content::WebPluginInfo plugin;
     std::string actual_mime_type;
     EXPECT_TRUE(context_.FindEnabledPlugin(
         0, GURL(), GURL(), "foo/bar", &status, &plugin, &actual_mime_type,
@@ -139,7 +148,7 @@
   filter_.set_plugin_enabled(foo_plugin_path_, false);
   {
     ChromeViewHostMsg_GetPluginInfo_Status status;
-    webkit::WebPluginInfo plugin;
+    content::WebPluginInfo plugin;
     std::string actual_mime_type;
     EXPECT_TRUE(context_.FindEnabledPlugin(
         0, GURL(), GURL(), "foo/bar", &status, &plugin, &actual_mime_type,
@@ -151,7 +160,7 @@
   filter_.set_plugin_enabled(bar_plugin_path_, false);
   {
     ChromeViewHostMsg_GetPluginInfo_Status status;
-    webkit::WebPluginInfo plugin;
+    content::WebPluginInfo plugin;
     std::string actual_mime_type;
     std::string identifier;
     string16 plugin_name;
@@ -163,7 +172,7 @@
   }
   {
     ChromeViewHostMsg_GetPluginInfo_Status status;
-    webkit::WebPluginInfo plugin;
+    content::WebPluginInfo plugin;
     std::string actual_mime_type;
     EXPECT_FALSE(context_.FindEnabledPlugin(
         0, GURL(), GURL(), "baz/blurp", &status, &plugin, &actual_mime_type,
@@ -172,3 +181,5 @@
     EXPECT_EQ(FILE_PATH_LITERAL(""), plugin.path.value());
   }
 }
+
+#endif
diff --git a/chrome/browser/renderer_host/web_cache_manager.cc b/chrome/browser/renderer_host/web_cache_manager.cc
index 758b4e1..d2267bd 100644
--- a/chrome/browser/renderer_host/web_cache_manager.cc
+++ b/chrome/browser/renderer_host/web_cache_manager.cc
@@ -315,15 +315,13 @@
       // This is the capacity this renderer has been allocated.
       size_t capacity = allocation->second;
 
-      // We don't reserve any space for dead objects in the cache.  Instead, we
-      // prefer to keep live objects around.  There is probably some performance
+      // We don't reserve any space for dead objects in the cache. Instead, we
+      // prefer to keep live objects around. There is probably some performance
       // tuning to be done here.
       size_t min_dead_capacity = 0;
 
-      // We allow the dead objects to consume all of the cache, if the renderer
-      // so desires.  If we wanted this memory, we would have set the total
-      // capacity lower.
-      size_t max_dead_capacity = capacity;
+      // We allow the dead objects to consume up to half of the cache capacity.
+      size_t max_dead_capacity = capacity / 2;
 
       host->Send(new ChromeViewMsg_SetCacheCapacities(min_dead_capacity,
                                                       max_dead_capacity,
diff --git a/chrome/browser/repost_form_warning_controller.cc b/chrome/browser/repost_form_warning_controller.cc
index 0d9ac56..517036a 100644
--- a/chrome/browser/repost_form_warning_controller.cc
+++ b/chrome/browser/repost_form_warning_controller.cc
@@ -15,8 +15,7 @@
 
 RepostFormWarningController::RepostFormWarningController(
     content::WebContents* web_contents)
-    : TabModalConfirmDialogDelegate(web_contents),
-      content::WebContentsObserver(web_contents) {
+    : content::WebContentsObserver(web_contents) {
 }
 
 RepostFormWarningController::~RepostFormWarningController() {
@@ -45,7 +44,9 @@
 #endif  // defined(TOOLKIT_GTK)
 
 void RepostFormWarningController::OnAccepted() {
+  operations_delegate()->SetPreventCloseOnLoadStart(true);
   web_contents()->GetController().ContinuePendingReload();
+  operations_delegate()->SetPreventCloseOnLoadStart(false);
 }
 
 void RepostFormWarningController::OnCanceled() {
diff --git a/chrome/browser/resources/OWNERS b/chrome/browser/resources/OWNERS
index f8194fa..bbebd98 100644
--- a/chrome/browser/resources/OWNERS
+++ b/chrome/browser/resources/OWNERS
@@ -1,6 +1,7 @@
 arv@chromium.org
 bauerb@chromium.org
 dbeam@chromium.org
+dubroy@chromium.org
 estade@chromium.org
 jhawkins@chromium.org
 nkostylev@chromium.org
diff --git a/chrome/browser/resources/bookmark_manager/js/main.js b/chrome/browser/resources/bookmark_manager/js/main.js
index 65e4053..9f58a2d 100644
--- a/chrome/browser/resources/bookmark_manager/js/main.js
+++ b/chrome/browser/resources/bookmark_manager/js/main.js
@@ -849,9 +849,7 @@
   lastDeletedNodes = [];
 
   function performDelete() {
-    selectedIds.forEach(function(id) {
-      chrome.bookmarks.removeTree(id);
-    });
+    chrome.bookmarkManagerPrivate.removeTrees(selectedIds);
     $('undo-delete-command').canExecuteChange();
     performGlobalUndo = undoDelete;
   }
diff --git a/chrome/browser/resources/chromeos/connectivity_diagnostics/manifest.json b/chrome/browser/resources/chromeos/connectivity_diagnostics/manifest.json
new file mode 100644
index 0000000..345a72c
--- /dev/null
+++ b/chrome/browser/resources/chromeos/connectivity_diagnostics/manifest.json
@@ -0,0 +1,31 @@
+{
+  "key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDGJWLUb83WKoDeODlrPIZu60M8bzbvrkg3Jf/5aO3ux2FL+G+/BO4Vyt/J0t8lXBtnTOvHo6KPpA042PyE9xMdlufFnJqEkvPXNzRlBWeVQqFHbMWE6o/x8diG69dNmHyFYcUjjFFDk2X2GOLQXNUGJQ6MIikbdzoWdLGttmhAIwIDAQAB",
+  "manifest_version": 2,
+  "name": "Chrome Connectivity Debugger (Dev)",
+  "version": "0.2.8",
+  "minimum_chrome_version": "27",
+  "offline_enabled": true,
+  "default_locale": "en",
+  "icons": {
+    "128": "img/icon_128.png",
+    "16": "img/icon_16.png"
+  },
+  "permissions" : [
+   { "socket" : [
+     "tcp-connect:*:443",
+     "tcp-connect:*:80",
+     "tcp-connect:*:25",
+     "udp-bind:*",
+     "udp-send-to:*:53"
+   ]},
+   "clipboardWrite",
+   "experimental",
+   "http://*.google.com/*",
+   "http://www.yahoo.com/*"
+  ],
+  "app": {
+    "background": {
+      "scripts": ["background.js"]
+    }
+  }
+}
diff --git a/chrome/browser/resources/chromeos/login/display_manager.js b/chrome/browser/resources/chromeos/login/display_manager.js
index eb87f87..9ddeee2 100644
--- a/chrome/browser/resources/chromeos/login/display_manager.js
+++ b/chrome/browser/resources/chromeos/login/display_manager.js
@@ -415,7 +415,9 @@
       var dot = document.createElement('div');
       dot.id = screenId + '-dot';
       dot.className = 'progdot';
-      $('progress-dots').appendChild(dot);
+      var progressDots = $('progress-dots');
+      if (progressDots)
+        progressDots.appendChild(dot);
 
       this.appendButtons_(el.buttons, screenId);
     },
diff --git a/chrome/browser/resources/chromeos/login/header_bar.js b/chrome/browser/resources/chromeos/login/header_bar.js
index efeed3d..fb8854e 100644
--- a/chrome/browser/resources/chromeos/login/header_bar.js
+++ b/chrome/browser/resources/chromeos/login/header_bar.js
@@ -44,7 +44,6 @@
           this.handleSignoutClick_);
       $('cancel-multiple-sign-in-button').addEventListener('click',
           this.handleCancelMultipleSignInClick_);
-
       if (document.documentElement.getAttribute('screen') == 'login')
         login.AppsMenuButton.decorate($('show-apps-button'));
     },
diff --git a/chrome/browser/resources/chromeos/login/screen_account_picker.js b/chrome/browser/resources/chromeos/login/screen_account_picker.js
index 61b9d85..ab2d4ec 100644
--- a/chrome/browser/resources/chromeos/login/screen_account_picker.js
+++ b/chrome/browser/resources/chromeos/login/screen_account_picker.js
@@ -74,7 +74,9 @@
       // hide the add user button and activate the locked user's pod.
       var lockedPod = podRow.lockedPod;
       $('add-user-header-bar-item').hidden = !!lockedPod;
-      $('sign-out-user-item').hidden = !lockedPod;
+      var signOutUserItem = $('sign-out-user-item');
+      if (signOutUserItem)
+        signOutUserItem.hidden = !lockedPod;
       // In case of the preselected pod onShow will be called once pod
       // receives focus.
       if (!podRow.preselectedPod)
diff --git a/chrome/browser/resources/chromeos/login/screen_gaia_signin.js b/chrome/browser/resources/chromeos/login/screen_gaia_signin.js
index fae6e89..1a00aa7 100644
--- a/chrome/browser/resources/chromeos/login/screen_gaia_signin.js
+++ b/chrome/browser/resources/chromeos/login/screen_gaia_signin.js
@@ -187,6 +187,11 @@
       chrome.send('loginUIStateChanged', ['gaia-signin', true]);
       $('login-header-bar').signinUIState = SIGNIN_UI_STATE.GAIA_SIGNIN;
 
+      // Ensure that GAIA signin (or loading UI) is actually visible.
+      window.webkitRequestAnimationFrame(function() {
+        chrome.send('loginVisible', ['gaia-loading']);
+      });
+
       // Announce the name of the screen, if accessibility is on.
       $('gaia-signin-aria-label').setAttribute(
           'aria-label', loadTimeData.getString('signinScreenTitle'));
@@ -431,7 +436,6 @@
      * @param {number} error Error code.
      */
     onFrameError: function(error) {
-      console.error('Gaia frame error = ' + error);
       this.error_ = error;
       chrome.send('frameLoadingCompleted', [this.error_]);
     },
diff --git a/chrome/browser/resources/chromeos/login/user_pod_row.js b/chrome/browser/resources/chromeos/login/user_pod_row.js
index 5d62216..5482a9c 100644
--- a/chrome/browser/resources/chromeos/login/user_pod_row.js
+++ b/chrome/browser/resources/chromeos/login/user_pod_row.js
@@ -154,10 +154,12 @@
           this.handleRemoveCommandKeyDown_.bind(this));
       this.actionBoxMenuRemoveElement.addEventListener('blur',
           this.handleRemoveCommandBlur_.bind(this));
-      this.actionBoxRemoveManagedUserWarningButtonElement.addEventListener(
-          'click',
-          this.handleRemoveUserConfirmationClick_.bind(this));
 
+      if (this.actionBoxRemoveManagedUserWarningButtonElement) {
+        this.actionBoxRemoveManagedUserWarningButtonElement.addEventListener(
+            'click',
+            this.handleRemoveUserConfirmationClick_.bind(this));
+      }
     },
 
     /**
@@ -332,12 +334,19 @@
           '?id=' + UserPod.userImageSalt_[this.user.username];
 
       this.nameElement.textContent = this.user_.displayName;
-      this.actionBoxAreaElement.hidden = this.user_.publicAccount;
-      this.actionBoxMenuRemoveElement.hidden = !this.user_.canRemove;
       this.signedInIndicatorElement.hidden = !this.user_.signedIn;
 
       var needSignin = this.needGaiaSignin;
       this.passwordElement.hidden = needSignin;
+      this.signinButtonElement.hidden = !needSignin;
+
+      this.updateActionBoxArea();
+    },
+
+    updateActionBoxArea: function() {
+      this.actionBoxAreaElement.hidden = this.user_.publicAccount;
+      this.actionBoxMenuRemoveElement.hidden = !this.user_.canRemove;
+
       this.actionBoxAreaElement.setAttribute(
           'aria-label', loadTimeData.getStringF(
               'podMenuButtonAccessibleName', this.user_.emailAddress));
@@ -355,7 +364,6 @@
           loadTimeData.getString('removeUser');
       this.passwordElement.setAttribute('aria-label', loadTimeData.getStringF(
           'passwordFieldAccessibleName', this.user_.emailAddress));
-      this.signinButtonElement.hidden = !needSignin;
       this.userTypeIconAreaElement.hidden = !this.user_.locallyManagedUser;
     },
 
@@ -408,7 +416,8 @@
 
       if (active) {
         this.actionBoxMenuRemoveElement.hidden = !this.user_.canRemove;
-        this.actionBoxRemoveManagedUserWarningElement.hidden = true;
+        if (this.actionBoxRemoveManagedUserWarningElement)
+          this.actionBoxRemoveManagedUserWarningElement.hidden = true;
 
         // Clear focus first if another pod is focused.
         if (!this.parentNode.isFocused(this)) {
@@ -619,6 +628,7 @@
     handleMouseDown_: function(e) {
       if (this.parentNode.disabled)
         return;
+
       if (!this.signinButtonElement.hidden && !this.isActionBoxMenuActive) {
         this.showSigninUI();
         // Prevent default so that we don't trigger 'focus' event.
@@ -809,6 +819,79 @@
   };
 
   /**
+   * Creates a user pod to be used only in desktop chrome.
+   * @constructor
+   * @extends {UserPod}
+   */
+  var DesktopUserPod = cr.ui.define(function() {
+    // Don't just instantiate a UserPod(), as this will call decorate() on the
+    // parent object, and add duplicate event listeners.
+    var node = $('user-pod-template').cloneNode(true);
+    node.removeAttribute('id');
+    return node;
+  });
+
+  DesktopUserPod.prototype = {
+    __proto__: UserPod.prototype,
+
+    /** @override */
+    decorate: function() {
+      UserPod.prototype.decorate.call(this);
+    },
+
+    /** @override */
+    focusInput: function() {
+      var isLockedUser = this.user.needsSignin;
+      this.signinButtonElement.hidden = isLockedUser;
+      this.passwordElement.hidden = !isLockedUser;
+
+      // Move tabIndex from the whole pod to the main input.
+      this.tabIndex = -1;
+      this.mainInput.tabIndex = UserPodTabOrder.POD_INPUT;
+      this.mainInput.focus();
+    },
+
+    /** @override */
+    update: function() {
+      // TODO(noms): Use the actual profile avatar for local profiles once the
+      // new, non-pixellated avatars are available.
+      this.imageElement.src = this.user.emailAddress == '' ?
+          'chrome://theme/IDR_USER_MANAGER_DEFAULT_AVATAR' :
+          this.user.userImage;
+      this.nameElement.textContent = this.user_.displayName;
+      var isLockedUser = this.user.needsSignin;
+      this.passwordElement.hidden = !isLockedUser;
+      this.signinButtonElement.hidden = isLockedUser;
+
+      UserPod.prototype.updateActionBoxArea.call(this);
+    },
+
+    /** @override */
+    activate: function() {
+      Oobe.launchUser(this.user.emailAddress, this.user.displayName);
+      return true;
+    },
+
+    /** @override */
+    handleMouseDown_: function(e) {
+      if (this.parentNode.disabled)
+        return;
+
+      // Don't sign in until the user presses the button. Just activate the pod.
+      Oobe.clearErrors();
+      this.parentNode.lastFocusedPod_ =
+          this.parentNode.getPodWithUsername_(this.user.emailAddress);
+    },
+
+    /** @override */
+    handleRemoveCommandClick_: function(e) {
+      //TODO(noms): Add deletion confirmation overlay before attempting
+      // to delete the user.
+      UserPod.prototype.handleRemoveCommandClick_.call(this, e);
+    },
+  };
+
+  /**
    * Creates a new pod row element.
    * @constructor
    * @extends {HTMLDivElement}
@@ -914,7 +997,9 @@
      */
     createUserPod: function(user) {
       var userPod;
-      if (user.publicAccount)
+      if (user.isDesktopUser)
+        userPod = new DesktopUserPod({user: user});
+      else if (user.publicAccount)
         userPod = new PublicAccountUserPod({user: user});
       else
         userPod = new UserPod({user: user});
diff --git a/chrome/browser/resources/file_manager/css/file_manager.css b/chrome/browser/resources/file_manager/css/file_manager.css
index e4b8a8a..df84340 100644
--- a/chrome/browser/resources/file_manager/css/file_manager.css
+++ b/chrome/browser/resources/file_manager/css/file_manager.css
@@ -769,7 +769,8 @@
   width: 22px;
 }
 
-#spinner-container {
+#spinner-container,
+.spinner-container {
   -webkit-box-align: center;
   -webkit-box-pack: center;
   bottom: 0;
@@ -1891,3 +1892,30 @@
 .error-dialog-frame .cr-dialog-text {
   text-align: center;
 }
+
+.cr-dialog-frame.share-dialog-frame {
+  background-color: white;
+  width: auto;
+}
+
+.share-dialog-webview-wrapper {
+  height: 100px;
+  margin-top: 10px;
+  min-width: 300px;
+  overflow: hidden;
+  transition: height 200ms ease;
+}
+
+.share-dialog-webview {
+  height: 100%;
+  width: 100%;
+}
+
+.share-dialog-webview-wrapper:not(.loaded) .share-dialog-webview {
+  visibility: hidden;
+}
+
+.share-dialog-frame .cr-dialog-text,
+.share-dialog-frame .cr-dialog-buttons {
+  display: none;
+}
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 d185c7b..9fdd912 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 5de5c7e..79f492e 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 eee68dd..00cbed6 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/button.png b/chrome/browser/resources/file_manager/images/common/button.png
index 4de5ff0..76bc97e 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 c24d7cc..34965e0 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 c54d6fe..3c81b8b 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/checkbox_white_checked.png b/chrome/browser/resources/file_manager/images/common/checkbox_white_checked.png
index c095d6c..b24de30 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/files/file_types/100/gtable_white.png b/chrome/browser/resources/file_manager/images/files/file_types/100/gtable_white.png
index f534641..9198c9e 100644
--- 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
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
index 540fdc2..0252d4c 100644
--- 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
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 316e8a0..be900c8 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/search_icon_active.png b/chrome/browser/resources/file_manager/images/files/ui/2x/search_icon_active.png
index 80d733b..d58cd10 100644
--- 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
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/drive_logo.png b/chrome/browser/resources/file_manager/images/files/ui/drive_logo.png
index c5aef52..5e6fb3e 100644
--- a/chrome/browser/resources/file_manager/images/files/ui/drive_logo.png
+++ b/chrome/browser/resources/file_manager/images/files/ui/drive_logo.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 85f8c11..1825168 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/volumes/2x/black_shared.png b/chrome/browser/resources/file_manager/images/files/volumes/2x/black_shared.png
index 79b9edc..5c30267 100644
--- 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
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 6490950..6202fa9 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_swne.png b/chrome/browser/resources/file_manager/images/gallery/2x/cursor_swne.png
index 5bdae73..9153d7b 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/icon_print.png b/chrome/browser/resources/file_manager/images/gallery/2x/icon_print.png
index 95923a9..b5a9be0 100644
--- a/chrome/browser/resources/file_manager/images/gallery/2x/icon_print.png
+++ 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
index d4ac79f..048a341 100644
--- 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
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 e7bf684..db2c0b0 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 4ebbb68..63ab3ab 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_selected.png b/chrome/browser/resources/file_manager/images/gallery/2x/icon_rotate_selected.png
index 1990a63..b3a9bf6 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_undo_selected.png b/chrome/browser/resources/file_manager/images/gallery/2x/icon_undo_selected.png
index 3c838c6..92d3a01 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/butterbar_close_button.png b/chrome/browser/resources/file_manager/images/gallery/butterbar_close_button.png
index bc26727..3c65c23 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_nwse.png b/chrome/browser/resources/file_manager/images/gallery/cursor_nwse.png
index 3f3e33c..87fb564 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/icon_print.png b/chrome/browser/resources/file_manager/images/gallery/icon_print.png
index ec5418e..b235536 100644
--- a/chrome/browser/resources/file_manager/images/gallery/icon_print.png
+++ 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
index 89e302e..07b5f43 100644
--- a/chrome/browser/resources/file_manager/images/gallery/icon_print_selected.png
+++ 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_undo.png b/chrome/browser/resources/file_manager/images/gallery/icon_undo.png
index 333c455..79e3fdd 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/slideshow-pause.png b/chrome/browser/resources/file_manager/images/gallery/slideshow-pause.png
index ad3633f..2170ce9 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/icon256.png b/chrome/browser/resources/file_manager/images/icon256.png
index 2e50e0f..31864fb 100644
--- a/chrome/browser/resources/file_manager/images/icon256.png
+++ b/chrome/browser/resources/file_manager/images/icon256.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 e3b7973..a8f648a 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/media_loop_hover.png b/chrome/browser/resources/file_manager/images/media/2x/media_loop_hover.png
index cb2af67..b3a6c14 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_down.png b/chrome/browser/resources/file_manager/images/media/2x/media_next_down.png
index 79a370b..58d5bf7 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_pause_down.png b/chrome/browser/resources/file_manager/images/media/2x/media_pause_down.png
index 6f8f494..9caaf7a 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_slider_thumb.png b/chrome/browser/resources/file_manager/images/media/2x/media_slider_thumb.png
index 5a130bd..cd20aa2 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_sound_full_hover.png b/chrome/browser/resources/file_manager/images/media/2x/media_sound_full_hover.png
index e617eab..da31aa4 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_level2_hover.png b/chrome/browser/resources/file_manager/images/media/2x/media_sound_level2_hover.png
index 9966a5e..2e3f2e8 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 c518743..93ce5c1 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_hover.png b/chrome/browser/resources/file_manager/images/media/2x/media_volume_slider_thumb_hover.png
index ae16119..4d4243d 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/audio_player.png b/chrome/browser/resources/file_manager/images/media/audio_player.png
index 9134bde..6921db2 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/media_loop_hover.png b/chrome/browser/resources/file_manager/images/media/media_loop_hover.png
index 805d293..a0ed21f 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_sound_full_down.png b/chrome/browser/resources/file_manager/images/media/media_sound_full_down.png
index 1a185ed..55d77e4 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/js/directory_model.js b/chrome/browser/resources/file_manager/js/directory_model.js
index 46e6015..be32e57 100644
--- a/chrome/browser/resources/file_manager/js/directory_model.js
+++ b/chrome/browser/resources/file_manager/js/directory_model.js
@@ -291,6 +291,37 @@
 };
 
 /**
+ * Updates the selection by using the updateFunc and publish the change event.
+ * If updateFunc returns true, it force to dispatch the change event even if the
+ * selection index is not changed.
+ *
+ * @param {cr.ui.ListSingleSelectionModel} selection Selection to be updated.
+ * @param {function(): boolean} updateFunc Function updating the selection.
+ * @private
+ */
+DirectoryModel.prototype.updateSelectionAndPublishEvent_ =
+    function(selection, updateFunc) {
+  // Begin change.
+  selection.beginChange();
+
+  // If dispatchNeeded is true, we should ensure the change evnet is
+  // dispatched.
+  var dispatchNeeded = updateFunc();
+
+  // Check if the change event is dispatched in the endChange function
+  // or not.
+  var eventDispatched = function() { dispatchNeeded = false; };
+  selection.addEventListener('change', eventDispatched);
+  selection.endChange();
+  selection.removeEventListener('change', eventDispatched);
+
+  // If the change evnet have been already dispatched, dispatchNeeded is false.
+  if (dispatchNeeded) {
+    selection.dispatchEvent(selection.createChangeEvent('change'));
+  }
+};
+
+/**
  * Invoked when filters are changed.
  * @private
  */
@@ -592,31 +623,33 @@
  */
 DirectoryModel.prototype.replaceDirectoryContents_ = function(dirContents) {
   cr.dispatchSimpleEvent(this, 'begin-update-files');
-  this.fileListSelection_.beginChange();
+  this.updateSelectionAndPublishEvent_(this.fileListSelection_, function() {
+    var selectedPaths = this.getSelectedPaths_();
+    var selectedIndices = this.fileListSelection_.selectedIndexes;
 
-  var selectedPaths = this.getSelectedPaths_();
-  var selectedIndices = this.fileListSelection_.selectedIndexes;
+    // Restore leadIndex in case leadName no longer exists.
+    var leadIndex = this.fileListSelection_.leadIndex;
+    var leadPath = this.getLeadPath_();
 
-  // Restore leadIndex in case leadName no longer exists.
-  var leadIndex = this.fileListSelection_.leadIndex;
-  var leadPath = this.getLeadPath_();
+    this.currentDirContents_ = dirContents;
+    dirContents.replaceContextFileList();
 
-  this.currentDirContents_ = dirContents;
-  dirContents.replaceContextFileList();
+    this.setSelectedPaths_(selectedPaths);
+    this.fileListSelection_.leadIndex = leadIndex;
+    this.setLeadPath_(leadPath);
 
-  this.setSelectedPaths_(selectedPaths);
-  this.fileListSelection_.leadIndex = leadIndex;
-  this.setLeadPath_(leadPath);
-
-  // If nothing is selected after update, then select file next to the
-  // latest selection
-  if (this.fileListSelection_.selectedIndexes.length == 0 &&
-      selectedIndices.length != 0) {
-    var maxIdx = Math.max.apply(null, selectedIndices);
-    this.selectIndex(Math.min(maxIdx - selectedIndices.length + 2,
-                              this.getFileList().length) - 1);
-  }
-  this.fileListSelection_.endChange();
+    // If nothing is selected after update, then select file next to the
+    // latest selection
+    var forceChangeEvent = false;
+    if (this.fileListSelection_.selectedIndexes.length == 0 &&
+        selectedIndices.length != 0) {
+      var maxIdx = Math.max.apply(null, selectedIndices);
+      this.selectIndex(Math.min(maxIdx - selectedIndices.length + 2,
+                                this.getFileList().length) - 1);
+      forceChangeEvent = true;
+    }
+    return forceChangeEvent;
+  }.bind(this));
 
   cr.dispatchSimpleEvent(this, 'end-update-files');
 };
@@ -805,8 +838,8 @@
  * 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.
+ * @param {function(DirectoryEntry)} successCallback Success callback.
+ * @param {function(FileError)} errorCallback Error callback.
  */
 DirectoryModel.prototype.resolveDirectory = function(
     path, successCallback, errorCallback) {
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 7129546..5e55a13 100644
--- a/chrome/browser/resources/file_manager/js/file_copy_manager.js
+++ b/chrome/browser/resources/file_manager/js/file_copy_manager.js
@@ -4,12 +4,6 @@
 
 'use strict';
 
-if (chrome.extension) {
-  var getContentWindows = function() {
-    return chrome.extension.getViews();
-  };
-}
-
 /**
  * @constructor
  */
@@ -765,31 +759,8 @@
 
   var targetDirEntry = task.targetDirEntry;
   var originalPath = sourceEntry.fullPath.substr(sourcePath.length + 1);
-
   originalPath = task.applyRenames(originalPath);
 
-  var targetRelativePrefix = originalPath;
-  var targetExt = '';
-  var index = targetRelativePrefix.lastIndexOf('.');
-  if (index != -1) {
-    targetExt = targetRelativePrefix.substr(index);
-    targetRelativePrefix = targetRelativePrefix.substr(0, index);
-  }
-
-  // If file already exists, we try to make a copy named 'file (1).ext'.
-  // If file is already named 'file (X).ext', we go with 'file (X+1).ext'.
-  // If new name is still occupied, we increase the number up to 10 times.
-  var copyNumber = 0;
-  var match = /^(.*?)(?: \((\d+)\))?$/.exec(targetRelativePrefix);
-  if (match && match[2]) {
-    copyNumber = parseInt(match[2], 10);
-    targetRelativePrefix = match[1];
-  }
-
-  var targetRelativePath = '';
-  var renameTries = 0;
-  var firstExistingEntry = null;
-
   var onCopyCompleteBase = function(entry, size) {
     task.markEntryComplete(entry, size);
     successCallback(entry, size);
@@ -828,18 +799,6 @@
     onError('FILESYSTEM_ERROR', err);
   };
 
-  var onTargetExists = function(existingEntry) {
-    if (!firstExistingEntry)
-      firstExistingEntry = existingEntry;
-    renameTries++;
-    if (renameTries < 10) {
-      copyNumber++;
-      tryNextCopy();
-    } else {
-      onError('TARGET_EXISTS', firstExistingEntry);
-    }
-  };
-
   /**
    * Resolves the immediate parent directory entry and the file name of a
    * given path, where the path is specified by a directory (not necessarily
@@ -886,13 +845,7 @@
     }
   };
 
-  var onTargetNotResolved = function(err) {
-    // We expect to be unable to resolve the target file, since we're going
-    // to create it during the copy.  However, if the resolve fails with
-    // anything other than NOT_FOUND, that's trouble.
-    if (err.code != FileError.NOT_FOUND_ERR)
-      return onError('FILESYSTEM_ERROR', err);
-
+  var onDeduplicated = function(targetRelativePath) {
     if (task.move) {
       resolveDirAndBaseName(
           targetDirEntry, targetRelativePath,
@@ -1046,20 +999,8 @@
     }
   };
 
-  var tryNextCopy = function() {
-    targetRelativePath = targetRelativePrefix;
-    if (copyNumber > 0) {
-      targetRelativePath += ' (' + copyNumber + ')';
-    }
-    targetRelativePath += targetExt;
-
-    // Check to see if the target exists.  This kicks off the rest of the copy
-    // if the target is not found, or raises an error if it does.
-    util.resolvePath(targetDirEntry, targetRelativePath, onTargetExists,
-                     onTargetNotResolved);
-  };
-
-  tryNextCopy();
+  util.deduplicatePath(targetDirEntry, originalPath,
+                       onDeduplicated, onError);
 };
 
 /**
@@ -1089,27 +1030,12 @@
     destName = ((i < 0) ? basename : basename.substr(0, i));
   }
 
-  var copyNumber = 0;
-  var firstExistingEntry = null;
-  var destPath = destName + '.zip';
-
   var onError = function(reason, data) {
     self.log_('serviceZipTask error: ' + reason + ':', data);
     errorCallback(new FileCopyManager.Error(reason, data));
   };
 
-  var onTargetExists = function(existingEntry) {
-    if (copyNumber < 10) {
-      if (!firstExistingEntry)
-        firstExistingEntry = existingEntry;
-      copyNumber++;
-      tryZipSelection();
-    } else {
-      onError('TARGET_EXISTS', firstExistingEntry);
-    }
-  };
-
-  var onTargetNotResolved = function() {
+  var onDeduplicated = function(destPath) {
     var onZipSelectionComplete = function(success) {
       if (success) {
         self.sendProgressEvent_('SUCCESS');
@@ -1125,17 +1051,8 @@
         onZipSelectionComplete);
   };
 
-  var tryZipSelection = function() {
-    if (copyNumber > 0)
-      destPath = destName + ' (' + copyNumber + ').zip';
-
-    // Check if the target exists. This kicks off the rest of the zip file
-    // creation if the target is not found, or raises an error if it does.
-    util.resolvePath(task.targetDirEntry, destPath, onTargetExists,
-                     onTargetNotResolved);
-  };
-
-  tryZipSelection();
+  util.deduplicatePath(
+      task.targetDirEntry, destName + '.zip', onDeduplicated, onError);
 };
 
 /**
diff --git a/chrome/browser/resources/file_manager/js/file_copy_manager_wrapper.js b/chrome/browser/resources/file_manager/js/file_copy_manager_wrapper.js
index 4172a16..f955ff4 100644
--- a/chrome/browser/resources/file_manager/js/file_copy_manager_wrapper.js
+++ b/chrome/browser/resources/file_manager/js/file_copy_manager_wrapper.js
@@ -55,30 +55,10 @@
  * @private
  */
 FileCopyManagerWrapper.prototype.getCopyManagerAsync_ = function(callback) {
-  var MAX_RETRIES = 10;
-  var TIMEOUT = 100;
-
-  var retries = 0;
-
-  var tryOnce = function() {
-    var onGetBackgroundPage = function(bg) {
-      if (bg) {
-        var fileCopyManager = bg.FileCopyManager.getInstance();
-        fileCopyManager.initialize(callback.bind(this, fileCopyManager));
-        return;
-      }
-      if (++retries < MAX_RETRIES)
-        setTimeout(tryOnce, TIMEOUT);
-      else
-        console.error('Can\'t get copy manager.');
-    };
-    if (chrome.runtime && chrome.runtime.getBackgroundPage)
-      chrome.runtime.getBackgroundPage(onGetBackgroundPage);
-    else
-      onGetBackgroundPage(chrome.extension.getBackgroundPage());
-  };
-
-  tryOnce();
+  chrome.runtime.getBackgroundPage(function(backgroundPage) {
+    var fileCopyManager = backgroundPage.FileCopyManager.getInstance();
+    fileCopyManager.initialize(callback.bind(this, fileCopyManager));
+  });
 };
 
 /**
diff --git a/chrome/browser/resources/file_manager/js/file_grid.js b/chrome/browser/resources/file_manager/js/file_grid.js
index bb08940..5cbe2ff 100644
--- a/chrome/browser/resources/file_manager/js/file_grid.js
+++ b/chrome/browser/resources/file_manager/js/file_grid.js
@@ -57,7 +57,7 @@
 /**
  * Updates items to reflect metadata changes.
  * @param {string} type Type of metadata changed.
- * @param {Object<string, Object>} props Map from entry URLs to metadata props.
+ * @param {Object.<string, Object>} props Map from entry URLs to metadata props.
  */
 FileGrid.prototype.updateListItemsMetadata = function(type, props) {
   var boxes = this.querySelectorAll('.img-container');
@@ -198,6 +198,10 @@
 FileGrid.Item.prototype.__proto__ = cr.ui.ListItem.prototype;
 
 Object.defineProperty(FileGrid.Item.prototype, 'label', {
+  /**
+   * @this {FileGrid.Item}
+   * @return {string} Label of the item.
+   */
   get: function() {
     return this.querySelector('filename-label').textContent;
   }
diff --git a/chrome/browser/resources/file_manager/js/file_manager.js b/chrome/browser/resources/file_manager/js/file_manager.js
index 4a722bf..823d2a7 100644
--- a/chrome/browser/resources/file_manager/js/file_manager.js
+++ b/chrome/browser/resources/file_manager/js/file_manager.js
@@ -238,8 +238,8 @@
 
   /**
    * Changed metadata observers for the new directory.
-   * @override
-   * @param {?DirectoryEntry} entry New watched directory entry.
+   *
+   * @param {DirectoryEntry} entry New watched directory entry.
    * @override
    */
   FileManager.MetadataFileWatcher.prototype.changeWatchedEntry = function(
@@ -332,6 +332,15 @@
       }.bind(this));
     }.bind(this));
 
+    // TODO(yoshiki): Remove this after launching folder shortcuts feature.
+    group.add(function(done) {
+      chrome.commandLinePrivate.hasSwitch(
+          'file-manager-enable-folder-shortcuts', function(flag) {
+        this.isFolderShortcutsEnabled_ = flag;
+        done();
+      }.bind(this));
+    }.bind(this));
+
     group.run(callback);
   };
 
@@ -888,9 +897,11 @@
     var d = cr.ui.dialogs;
     d.BaseDialog.OK_LABEL = str('OK_LABEL');
     d.BaseDialog.CANCEL_LABEL = str('CANCEL_LABEL');
+    this.error = new ErrorDialog(this.dialogDom_);
     this.alert = new d.AlertDialog(this.dialogDom_);
     this.confirm = new d.ConfirmDialog(this.dialogDom_);
     this.prompt = new d.PromptDialog(this.dialogDom_);
+    this.shareDialog_ = new ShareDialog(this.dialogDom_, this.metadataCache_);
     this.defaultTaskPicker =
         new cr.filebrowser.DefaultActionDialog(this.dialogDom_);
   };
@@ -1149,7 +1160,7 @@
 
     this.directoryModel_.start();
 
-    this.pinnedFolderModel_ = new cr.ui.ArrayDataModel([]);
+    this.folderShortcutsModel_ = new FolderShortcutsDataModel();
 
     this.selectionHandler_ = new FileSelectionHandler(this);
     this.selectionHandler_.addEventListener('show-preview-panel',
@@ -1245,7 +1256,7 @@
     this.volumeList_ = this.dialogDom_.querySelector('#volume-list');
     VolumeList.decorate(this.volumeList_,
                         this.directoryModel_,
-                        this.pinnedFolderModel_);
+                        this.folderShortcutsModel_);
   };
 
   /**
@@ -1865,7 +1876,7 @@
   /**
    * @param {string} type Type of metadata changed.
    * @param {Array.<string>} urls Array of urls.
-   * @param {Object<string, Object>} props Map from entry URLs to metadata
+   * @param {Object.<string, Object>} props Map from entry URLs to metadata
    *     props.
    * @private
    */
@@ -2066,7 +2077,7 @@
   };
 
   FileManager.prototype.isDriveEnabled = function() {
-    // TODO(kinaba): remove the "!shouldReturnLocalPath &&" condition once
+    // TODO(kinaba): Remove the "!shouldReturnLocalPath &&" condition once
     // crbug.com/140425 is done.
     return !this.params_.shouldReturnLocalPath &&
         (!('driveEnabled' in this.preferences_) ||
@@ -2163,7 +2174,7 @@
 
   /**
    * Return full path of the current directory or null.
-   * @return {string=} The full path of the current directory.
+   * @return {?string} The full path of the current directory.
    */
   FileManager.prototype.getCurrentDirectory = function() {
     return this.directoryModel_ &&
@@ -2205,10 +2216,28 @@
   };
 
   /**
-   * Shows the share dialog for the selected file.
+   * Shows the share dialog for the selected file or directory.
    */
   FileManager.prototype.shareSelection = function() {
-    // TODO(mtomasz): Implement it. crbug.com/141396
+    var entries = this.getSelection().entries;
+    if (entries.length != 1) {
+      console.warn('Unable to share multiple items at once.');
+      return;
+    }
+    this.shareDialog_.show(entries[0], function() {
+      this.error.show(str('SHARE_ERROR'));
+    }.bind(this));
+  };
+
+  /**
+   * Folder shared feature is under development and hidden behind flag. This
+   * method returns if the feature is explicitly enabled by the flag or not.
+   * TODO(yoshiki): Remove this after launching folder feature feature.
+   *
+   * @return {boolena} True if the flag is enabled.
+   */
+  FileManager.prototype.isFolderShortcutsEnabled = function() {
+    return this.isFolderShortcutsEnabled_;
   };
 
   /**
@@ -2221,8 +2250,7 @@
     if (this.isFolderPinned(entry.fullPath))
       return;
 
-    this.pinnedFolderModel_.splice(0, 0, entry.fullPath);
-    this.pinnedFolderModel_.sort('name', 'asc');
+    this.folderShortcutsModel_.add(entry.fullPath);
   };
 
   /**
@@ -2230,13 +2258,7 @@
    * @param {string} path Path of the folder to be checked.
    */
   FileManager.prototype.isFolderPinned = function(path) {
-    for (var i = 0; i < this.pinnedFolderModel_.length; i++) {
-      var pinnedPath = this.pinnedFolderModel_.item(i);
-      if (pinnedPath == path) {
-        return true;
-      }
-    }
-    return false;
+    return this.folderShortcutsModel_.exists(path);
   };
 
   /**
@@ -2244,13 +2266,7 @@
    * @param {string} path Path of the pinned folder to be unpinnned.
    */
   FileManager.prototype.unpinFolder = function(path) {
-    for (var i = 0; i < this.pinnedFolderModel_.length; i++) {
-      var pinnedPath = this.pinnedFolderModel_.item(i);
-      if (pinnedPath == path) {
-        this.pinnedFolderModel_.splice(i, 1);
-        return;
-      }
-    }
+    this.folderShortcutsModel_.remove(path);
   };
 
   /**
@@ -3892,6 +3908,10 @@
    */
   FileManager.prototype.setCtrlKeyPressed_ = function(flag) {
     this.ctrlKeyPressed_ = flag;
-    this.document_.querySelector('#drive-clear-local-cache').canExecuteChange();
+    // Before the DOM is constructed, the key event can be handled.
+    var cacheClearCommand =
+        this.document_.querySelector('#drive-clear-local-cache');
+    if (cacheClearCommand)
+      cacheClearCommand.canExecuteChange();
   };
 })();
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 8e12f9c..f8c8b8d 100644
--- a/chrome/browser/resources/file_manager/js/file_manager_commands.js
+++ b/chrome/browser/resources/file_manager/js/file_manager_commands.js
@@ -419,7 +419,7 @@
   execute: function(event, fileManager) {
     var pin = !event.command.checked;
     event.command.checked = pin;
-    var entries = this.getTargetEntries_();
+    var entries = Commands.togglePinnedCommand.getTargetEntries_();
     var currentEntry;
     var error = false;
     var steps = {
@@ -468,7 +468,7 @@
   },
 
   canExecute: function(event, fileManager) {
-    var entries = this.getTargetEntries_();
+    var entries = Commands.togglePinnedCommand.getTargetEntries_();
     var checked = true;
     for (var i = 0; i < entries.length; i++) {
       checked = checked && entries[i].pinned;
@@ -537,7 +537,8 @@
     var selection = fileManager.getSelection();
     event.canExecute = fileManager.isOnDrive() &&
         !fileManager.isDriveOffline() &&
-        selection && selection.totalCount == 1;
+        selection && selection.totalCount == 1 &&
+        selection.directoryCount == 0;
     event.command.setHidden(!fileManager.isOnDrive());
   }
 };
@@ -558,6 +559,12 @@
    * @param {FileManager} fileManager The file manager instance.
    */
   canExecute: function(event, fileManager) {
+    // TODO(yoshiki): remove this after launching folder shortcuts feature.
+    if (!fileManager.isFolderShortcutsEnabled()) {
+      event.command.setHidden(true);
+      return;
+    }
+
     var selection = fileManager.getSelection();
     var selectionEntries = selection.entries;
     var onlyOneFolderSelected =
@@ -589,6 +596,12 @@
    * @param {DirectoryTree} directoryTree Target directory tree.
    */
   canExecute: function(event, fileManager, directoryTree) {
+    // TODO(yoshiki): remove this after launching folder shortcut feature.
+    if (!fileManager.isFolderShortcutsEnabled()) {
+      event.command.setHidden(true);
+      return;
+    }
+
     var path = CommandUtil.getCommandRoot(event, directoryTree);
     var isPinned = path && !PathUtil.isRootPath(path);
     event.canExecute = isPinned;
diff --git a/chrome/browser/resources/file_manager/js/file_table.js b/chrome/browser/resources/file_manager/js/file_table.js
index cb4923b..c52818b 100644
--- a/chrome/browser/resources/file_manager/js/file_table.js
+++ b/chrome/browser/resources/file_manager/js/file_table.js
@@ -256,6 +256,10 @@
      * @type {number}
      */
     size: {
+      /**
+       * @this {FileTableColumnModel}
+       * @return {number} Number of columns.
+       */
       get: function() {
         return this.totalSize;
       }
@@ -266,6 +270,10 @@
      * @type {number}
      */
     totalSize: {
+      /**
+       * @this {FileTableColumnModel}
+       * @return {number} Number of columns.
+       */
       get: function() {
         return columns.length;
       }
@@ -273,11 +281,14 @@
 
     /**
      * Obtains a column by the specified horizontal positon.
-     * @param {number} x Horizontal position.
-     * @return {object} The object that contains column index, column width, and
-     *     hitPosition where the horizontal position is hit in the column.
      */
     getHitColumn: {
+      /**
+       * @this {FileTableColumnModel}
+       * @param {number} x Horizontal position.
+       * @return {object} The object that contains column index, column width,
+       *     and hitPosition where the horizontal position is hit in the column.
+       */
       value: function(x) {
         for (var i = 0; x >= this.columns_[i].width; i++) {
           x -= this.columns_[i].width;
@@ -313,9 +324,16 @@
       new AsyncUtil.Aggregation(self.relayoutImmediately_.bind(self));
 
   Object.defineProperty(self.list_, 'selectionModel', {
+    /**
+     * @this {cr.ui.List}
+     * @return {cr.ui.ListSelectionModel} The current selection model.
+     */
     get: function() {
       return this.selectionModel_;
     },
+    /**
+     * @this {cr.ui.List}
+     */
     set: function(value) {
       var sm = this.selectionModel;
       if (sm)
@@ -926,10 +944,17 @@
   li.setAttribute('role', 'option');
 
   Object.defineProperty(li, 'selected', {
+    /**
+     * @this {ListItem}
+     * @return {boolean} True if the list item is selected.
+     */
     get: function() {
       return this.hasAttribute('selected');
     },
 
+    /**
+     * @this {ListItem}
+     */
     set: function(v) {
       if (v)
         this.setAttribute('selected');
diff --git a/chrome/browser/resources/file_manager/js/file_tasks.js b/chrome/browser/resources/file_manager/js/file_tasks.js
index 329b29b..e6072ee 100644
--- a/chrome/browser/resources/file_manager/js/file_tasks.js
+++ b/chrome/browser/resources/file_manager/js/file_tasks.js
@@ -21,7 +21,7 @@
    * List of invocations to be called once tasks are available.
    *
    * @private
-   * @type {Array,<Object>}
+   * @type {Array.<Object>}
    */
   this.pendingInvocations_ = [];
 }
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 1d5a90a..3afc416 100644
--- a/chrome/browser/resources/file_manager/js/file_transfer_controller.js
+++ b/chrome/browser/resources/file_manager/js/file_transfer_controller.js
@@ -737,6 +737,7 @@
 
   /**
    * @this {FileTransferController}
+   * @return {boolean} True if the current directory is read only.
    */
   get readonly() {
     return this.directoryModel_.isReadOnly();
@@ -744,6 +745,7 @@
 
   /**
    * @this {FileTransferController}
+   * @return {boolean} True if the current directory is on Drive.
    */
   get isOnDrive() {
     return PathUtil.isDriveBasedPath(this.directoryModel_.getCurrentRootPath());
@@ -762,7 +764,7 @@
 
   /**
    * @this {FileTransferController}
-   * @type {Array.<Entry>}
+   * @return {Array.<Entry>} Array of the selected entries.
    */
   get selectedEntries_() {
     var list = this.directoryModel_.getFileList();
diff --git a/chrome/browser/resources/file_manager/js/folder_shortcuts_data_model.js b/chrome/browser/resources/file_manager/js/folder_shortcuts_data_model.js
new file mode 100644
index 0000000..271b738
--- /dev/null
+++ b/chrome/browser/resources/file_manager/js/folder_shortcuts_data_model.js
@@ -0,0 +1,345 @@
+// 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.
+
+/**
+ * Basic sorted array model using chrome.storage as a backend.
+ *
+ * @param {string} type Type of backend. Should be "sync" or "local".
+ * @param {string} name Name of the model.
+ * @constructor
+ * @extends {cr.EventTarget}
+ */
+function StoredSortedArray(type, name) {
+  this.type_ = type;
+  this.name_ = name;
+  this.array_ = [];
+  this.storage_ = (type == 'sync') ? chrome.storage.sync : chrome.storage.local;
+
+  // Loads the contents from the storage to initialize the array.
+  this.storage_.get(name, function(value) {
+    if (!(name in value))
+      return;
+
+    // Since the value comes from outer resource, we have to check it just in
+    // case.
+    var list = value[name];
+    if (list instanceof Array) {
+      var changedEvent = new Event('changed');
+      changedEvent.permutation = this.createPermutation_(this.array_, list);
+
+      this.array_ = list;
+      this.dispatchEvent(changedEvent);
+    }
+  }.bind(this));
+
+  // Listening for changes in the storage.
+  chrome.storage.onChanged.addListener(function(changes, namespace) {
+    if (!(name in changes) || namespace != type)
+      return;
+
+    var list = changes[name].newValue;
+    // Since the value comes from outer resource, we have to check it just in
+    // case.
+    if (list instanceof Array) {
+      var changedEvent = new Event('changed');
+      changedEvent.permutation = this.createPermutation_(this.array_, list);
+
+      this.array_ = list;
+      this.dispatchEvent(changedEvent);
+    }
+  }.bind(this));
+}
+
+StoredSortedArray.prototype = {
+  __proto__: cr.EventTarget.prototype,
+
+  /**
+   * @return {number} Number of elements in the array.
+   */
+  get length() {
+    return this.array_.length;
+  },
+
+  /**
+   * @param {number} index Index of the element to be retrieved.
+   * @return {string} The value of the |index|-th element.
+   */
+  getItem: function(index) {
+    return this.array_[index];
+  },
+
+  /**
+   * @param {string} value Value of the element to be retrieved.
+   * @return {number} Index of the element with the specified |value|.
+   */
+  getIndex: function(value) {
+    for (var i = 0; i < this.length; i++) {
+      if (this.array_[i].localeCompare(value) == 0) {
+        return i;
+      }
+    }
+    return -1;
+  },
+
+  /**
+   * Adds the given item to the array.
+   * @param {string} value Value to be added into the array.
+   * @return {number} Index in the list which the element added to.
+   */
+  add: function(value) {
+    var i = 0;
+    for (; i < this.length; i++) {
+      // Since the array is sorted, new item will be added just before the first
+      // larger item. If the same item exists, do nothing.
+      if (this.array_[i].localeCompare(value) == 0) {
+        return i;
+      } else if (this.array_[i].localeCompare(value) >= 0) {
+        this.array_.splice(i, 0, value);
+        break;
+      }
+    }
+    // If value is not added yet, add it at the last.
+    if (i == this.length)
+      this.array_.push(value);
+    this.save_();
+    return i;
+  },
+
+  /**
+   * Removes the given item from the array.
+   * @param {string} value Value to be removed from the array.
+   * @return {number} Index in the list which the element removed from.
+   */
+  remove: function(value) {
+    var i = 0;
+    for (; i < this.length; i++) {
+      if (this.array_[i] == value) {
+        this.array_.splice(i, 1);
+        break;
+      }
+    }
+    this.save_();
+    return i;
+  },
+
+  /**
+   * Saves the current array to chrome.storage.
+   * @private
+   */
+  save_: function() {
+    var obj = {};
+    obj[this.name_] = this.array_;
+    this.storage_.set(obj, function() {});
+  },
+
+  /**
+   * Creates a permutation array for 'changed' event, which is compatible with
+   * a parmutation array used in cr/ui/array_data_model.js.
+   *
+   * @param {array} oldArray Previous array before changing.
+   * @param {array} newArray New array after changing.
+   * @return {Array.<number>} Created permutation array.
+   * @private
+   */
+  createPermutation_: function(oldArray, newArray) {
+    var oldIndex = 0;  // Index of oldArray.
+    var newIndex = 0;  // Index of newArray.
+
+    // Note that both new and old arrays are sorted.
+    var permutation = [];
+    for (; oldIndex < oldArray.length; oldIndex++) {
+      if (newIndex >= newArray.length) {
+        // oldArray[oldIndex] is deleted, which is not in the new array.
+        permutation[oldIndex] = -1;
+        continue;
+      }
+
+      while (newIndex < newArray.length) {
+        if (oldArray[oldIndex] == newArray[newIndex]) {
+          // Unchanged item, which exists in both new and old array. But the
+          // index may be changed.
+          permutation[oldIndex] = newIndex;
+          newIndex++;
+          break;
+        } else if (oldArray[oldIndex] < newArray[newIndex]) {
+          // oldArray[oldIndex] is deleted, which is not in the new array.
+          permutation[oldIndex] = -1;
+          break;
+        } else {  // oldArray[oldIndex] > newArray[newIndex]
+          // newArray[newIndex] is added, which is not in the old array.
+          newIndex++;
+        }
+      }
+    }
+    return permutation;
+  }
+};
+
+/**
+ * Model for the folder shortcuts.
+ * This list is the combined array of the following arrays.
+ *  1) syncable list of the folder shortcuts on drive
+ *  2) non-syncable list of the folder shortcuts on the other volumes.
+ *  Each array uses StoredSortedArray as implementation.
+ *
+ * @constructor
+ * @extends {cr.EventTarget}
+ */
+function FolderShortcutsDataModel() {
+  // Syncable array for Drive.
+  this.remoteList_ = new StoredSortedArray('sync', 'folder-shortcuts-list');
+  this.remoteList_.addEventListener(
+      'changed',
+      this.onArrayChanged_.bind(this, 'sync'));
+
+  // Syncable array for other volumes.
+  this.localList_ = new StoredSortedArray('local', 'folder-shortcuts-list');
+  this.localList_.addEventListener(
+      'changed',
+      this.onArrayChanged_.bind(this, 'local'));
+}
+
+/**
+ * Type of an event.
+ * @enum {number}
+ */
+FolderShortcutsDataModel.EventType = {
+  ADDED: 0,
+  REMOVED: 1
+};
+
+FolderShortcutsDataModel.prototype = {
+  __proto__: cr.EventTarget.prototype,
+
+  /**
+   * @return {number} The number of elements in the array.
+   */
+  get length() {
+    return this.remoteList_.length + this.localList_.length;
+  },
+
+  /**
+   * @param {string} path Path to be added.
+   */
+  add: function(path) {
+    if (PathUtil.isDriveBasedPath(path)) {
+      var index = this.remoteList_.add(path);
+      this.fireChangeEvents_('sync', index,
+                             FolderShortcutsDataModel.EventType.ADDED);
+    } else {
+      var index = this.localList_.add(path);
+      this.fireChangeEvents_('local', index,
+                             FolderShortcutsDataModel.EventType.ADDED);
+    }
+  },
+
+  /**
+   * @param {string} path Path to be removed.
+   */
+  remove: function(path) {
+    if (PathUtil.isDriveBasedPath(path)) {
+      var index = this.remoteList_.remove(path);
+      this.fireChangeEvents_('sync', index,
+                             FolderShortcutsDataModel.EventType.REMOVED);
+    } else {
+      var index = this.localList_.remove(path);
+      this.fireChangeEvents_('local', index,
+                             FolderShortcutsDataModel.EventType.REMOVED);
+    }
+  },
+
+  /**
+   * @param {string} path Path to be checked.
+   * @return {boolean} True if the given |path| exists in the array. False
+   *     otherwise.
+   */
+  exists: function(path) {
+    if (PathUtil.isDriveBasedPath(path)) {
+      var index = this.remoteList_.getIndex(path);
+      return (index >= 0);
+    } else {
+      var index = this.localList_.getIndex(path);
+      return (index >= 0);
+    }
+  },
+
+  /**
+   * @param {number} index Index of the element to be retrieved.
+   * @return {string=} The value of the |index|-th element.
+   */
+  item: function(index) {
+    if (0 <= index && index < this.remoteList_.length)
+      return this.remoteList_.getItem(index);
+    if (this.remoteList_.length <= index && index < this.length)
+      return this.localList_.getItem(index - this.remoteList_.length);
+    return undefined;
+  },
+
+  /**
+   * Invoked when any of the subarray is changed. This method propagates
+   * 'change' and 'permuted' events.
+   *
+   * @param {string} type Type of the array from which the change event comes.
+   * @param {Event} event The 'changed' event from the array.
+   */
+  onArrayChanged_: function(type, event) {
+    var changeEvent = new Event('change');
+    changeEvent.index = (type == 'sync') ? 0 : this.remoteList_.length;
+    this.dispatchEvent(changeEvent);
+
+    var permutedEvent = new Event('permuted');
+    permutedEvent.newLength = this.length;
+    permutedEvent.permutation = event.permutation;
+    this.dispatchEvent(permutedEvent);
+
+    // 'splice' and 'sorted' events are not implemented.
+  },
+
+  /**
+   * Fires 'change' and 'permuted' event.
+   *
+   * @param {string} type Type of the array from which the change event comes.
+   * @param {number} index Changed index in the array.
+   * @param {FolderShortcutsDataModel.EventType} type Type of the event.
+   */
+  fireChangeEvents_: function(type, index, eventType) {
+    var changedIndex = ((type == 'sync') ? 0 : this.remoteList_.length) + index;
+
+    var changeEvent = new Event('change');
+    changeEvent.index = changedIndex;
+    this.dispatchEvent(changeEvent);
+
+    var permutation = [];
+    if (eventType == FolderShortcutsDataModel.EventType.ADDED) {
+      // Old length should be (current length) - 1, since an item is added.
+      var oldLength = this.length - 1;
+      for (var i = 0; i < oldLength; i++) {
+        if (i < changedIndex)
+          permutation[i] = i;
+        else if (i == changedIndex)
+          permutation[i] = i + 1;
+        else
+          permutation[i] = i + 1;
+      }
+    } else {  // eventType == FolderShortcutsDataModel.EventType.REMOVED
+      // Old length should be (current length) + 1, since an item is removed.
+      var oldLength = this.length + 1;
+      for (var i = 0; i < oldLength; i++) {
+        if (i < changedIndex)
+          permutation[i] = i;
+        else if (i == changedIndex)
+          permutation[i] = -1;  // Item is removed.
+        else
+          permutation[i] = i - 1;
+      }
+    }
+
+    var permutedEvent = new Event('permuted');
+    permutedEvent.newLength = this.length;
+    permutedEvent.permutation = permutation;
+    this.dispatchEvent(permutedEvent);
+
+    // 'splice' and 'sorted' events are not implemented.
+  }
+};
diff --git a/chrome/browser/resources/file_manager/js/main_scripts.js b/chrome/browser/resources/file_manager/js/main_scripts.js
index a99f813..8c35a69 100644
--- a/chrome/browser/resources/file_manager/js/main_scripts.js
+++ b/chrome/browser/resources/file_manager/js/main_scripts.js
@@ -90,7 +90,10 @@
 //<include src="file_tasks.js"/>
 //<include src="file_transfer_controller.js"/>
 //<include src="file_type.js"/>
+//<include src="folder_shortcuts_data_model.js"/>
 //<include src="scrollbar.js"/>
+//<include src="share_client.js"/>
+//<include src="share_dialog.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_util.js b/chrome/browser/resources/file_manager/js/media/media_util.js
index 75b344a..e4e0e59 100644
--- a/chrome/browser/resources/file_manager/js/media/media_util.js
+++ b/chrome/browser/resources/file_manager/js/media/media_util.js
@@ -127,7 +127,7 @@
  * @param {ThumbnailLoader.FillMode} fillMode Fill mode.
  * @param {ThumbnailLoader.OptimizationMode=} opt_optimizationMode Optimization
  *     for downloading thumbnails. By default optimizations are disabled.
- * @param {function(Image, object} opt_onSuccess Success callback,
+ * @param {function(Image, Object)} opt_onSuccess Success callback,
  *     accepts the image and the transform.
  * @param {function} opt_onError Error callback.
  * @param {function} opt_onGeneric Callback for generic image used.
diff --git a/chrome/browser/resources/file_manager/js/metadata/metadata_cache.js b/chrome/browser/resources/file_manager/js/metadata/metadata_cache.js
index e64fba3..1c29a2d 100644
--- a/chrome/browser/resources/file_manager/js/metadata/metadata_cache.js
+++ b/chrome/browser/resources/file_manager/js/metadata/metadata_cache.js
@@ -818,6 +818,7 @@
     dirty: data.isDirty,
     availableOffline: DriveProvider.isAvailableOffline(data, url),
     availableWhenMetered: DriveProvider.isAvailableWhenMetered(data),
+    shareUrl: data.shareUrl || '',
     driveApps: data.driveApps || [],
     contentMimeType: data.contentMimeType || '',
     sharedWithMe: data.sharedWithMe
diff --git a/chrome/browser/resources/file_manager/js/share_client.js b/chrome/browser/resources/file_manager/js/share_client.js
new file mode 100644
index 0000000..d88f014
--- /dev/null
+++ b/chrome/browser/resources/file_manager/js/share_client.js
@@ -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.
+
+'use strict';
+
+/**
+ * @param {WebView} webView Web View tag.
+ * @param {string} url Share Url for an entry.
+ * @param {ShareClient.Observer} observer Observer instance.
+ * @constructor
+ */
+function ShareClient(webView, url, observer) {
+  this.webView_ = webView;
+  this.url_ = url;
+  this.observer_ = observer;
+  this.loaded_ = false;
+  this.loading_ = false;
+  this.onMessageBound_ = this.onMessage_.bind(this);
+  this.onLoadStopBound_ = this.onLoadStop_.bind(this);
+  this.onLoadAbortBound_ = this.onLoadAbort_.bind(this);
+}
+
+/**
+ * Source origin of the client.
+ * @type {string}
+ * @const
+ */
+ShareClient.SHARE_ORIGIN =
+    'chrome-extension://hhaomjibdihmijegdhdafkllkbggdgoj';
+
+/**
+ * Target origin of the embedded dialog.
+ * @type {string}
+ * @const
+ */
+ShareClient.SHARE_TARGET = 'https://drive.google.com';
+
+/**
+ * Observes for state changes of the embedded dialog.
+ * @interface
+ */
+ShareClient.Observer = function() {
+};
+
+/**
+ * Notifies about the embedded dialog being loaded.
+ */
+ShareClient.Observer.prototype.onLoaded = function() {
+};
+
+/**
+ * Notifies when the the embedded dialog failed to load.
+ */
+ShareClient.Observer.prototype.onLoadingFailed = function() {
+};
+
+/**
+ * Notifies about changed dimensions of the embedded dialog.
+ * @param {number} width Width in pixels.
+ * @param {number} height Height in pixels.
+ * @param {function()} callback Completion callback. Call when finished
+ *     handling the resize.
+ */
+ShareClient.Observer.prototype.onResized = function(width, height, callback) {
+};
+
+/**
+ * Notifies about the embedded dialog being closed.
+ */
+ShareClient.Observer.prototype.onClosed = function() {
+};
+
+/**
+ * Handles messages from the embedded dialog.
+ * @param {Event} e Message event.
+ * @private
+ */
+ShareClient.prototype.onMessage_ = function(e) {
+  if (e.origin != ShareClient.SHARE_TARGET)
+    return;
+  var data = JSON.parse(e.data);
+  switch (data.type) {
+    case 'resize':
+      this.observer_.onResized(data.args.width,
+                               data.args.height,
+                               this.postMessage_.bind(this, 'resizeComplete'));
+      break;
+    case 'prepareForVisible':
+      this.postMessage_('prepareComplete');
+      if (!this.loaded_) {
+        this.loading_ = false;
+        this.loaded_ = true;
+        this.observer_.onLoaded();
+      }
+      break;
+    case 'setVisible':
+      if (!data.args.visible)
+        this.observer_.onClosed();
+      break;
+  }
+};
+
+/**
+ * Handles completion of the web view request.
+ * @param {Event} e Message event.
+ * @private
+ */
+ShareClient.prototype.onLoadStop_ = function(e) {
+  this.postMessage_('makeBodyVisible');
+};
+
+/**
+ * Handles termination of the web view request.
+ * @param {Event} e Message event.
+ * @private
+ */
+ShareClient.prototype.onLoadAbort_ = function(e) {
+  this.observer_.onLoadFailed();
+};
+
+/**
+ * Sends a message to the embedded dialog.
+ * @param {string} type Message type.
+ * @param {Object=} opt_args Optional arguments.
+ * @private
+ */
+ShareClient.prototype.postMessage_ = function(type, opt_args) {
+  var message = {
+    type: type,
+    args: opt_args
+  };
+  this.webView_.contentWindow.postMessage(
+      JSON.stringify(message), ShareClient.SHARE_TARGET);
+};
+
+/**
+ * Loads the embedded dialog. Can be called only one.
+ */
+ShareClient.prototype.load = function() {
+  if (this.loading_ || this.loaded_)
+    throw new Error('Already loaded.');
+  this.loading_ = true;
+
+  window.addEventListener('message', this.onMessageBound_);
+  this.webView_.addEventListener('loadstop', this.onLoadStopBound_);
+  this.webView_.addEventListener('loadabort', this.onLoadAbortBound_);
+  this.webView_.setAttribute('src', this.url_);
+};
+
+/**
+ * Aborts loading of the embedded dialog and performs cleanup.
+ */
+ShareClient.prototype.abort = function() {
+  window.removeEventListener('message', this.onMessageBound_);
+  this.webView_.removeEventListener('loadstop', this.onLoadStopBound_);
+  this.webView_.removeEventListener(
+      'loadabort', this.onLoadAbortBound_);
+  this.webView_.stop();
+};
+
+/**
+ * Cleans the dialog by removing all handlers.
+ */
+ShareClient.prototype.dispose = function() {
+  this.abort();
+};
diff --git a/chrome/browser/resources/file_manager/js/share_dialog.js b/chrome/browser/resources/file_manager/js/share_dialog.js
new file mode 100644
index 0000000..852912e
--- /dev/null
+++ b/chrome/browser/resources/file_manager/js/share_dialog.js
@@ -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.
+
+'use strict';
+
+/**
+ * @param {HTMLElement} parentNode Node to be parent for this dialog.
+ * @param {MetadataCache} metadataCache Metadata cache.
+ * @constructor
+ * @extends {cr.ui.dialogs.BaseDialog}
+ * @implements {ShareClient.Observer}
+ */
+function ShareDialog(parentNode, metadataCache) {
+  this.queue_ = new AsyncUtil.Queue();
+  this.onQueueTaskFinished_ = null;
+  this.metadataCache_ = metadataCache;
+  this.shareClient_ = null;
+  this.spinner_ = null;
+  this.spinnerWrapper_ = null;
+  this.webViewWrapper_ = null;
+  this.webView_ = null;
+  this.failureTimeout_ = null;
+
+  cr.ui.dialogs.BaseDialog.call(this, parentNode);
+}
+
+/**
+ * Timeout for loading the share dialog before giving up.
+ * @type {number}
+ * @const
+ */
+ShareDialog.FAILURE_TIMEOUT = 5000;
+
+/**
+ * Wraps a Web View element and adds authorization headers to it.
+ * @param {origin} origin Origin to be authorized.
+ * @param {WebView} webView Web View element to be wrapped.
+ * @constructor
+ */
+ShareDialog.WebViewAuthorizer = function(origin, webView) {
+  this.origin_ = origin;
+  this.webView_ = webView;
+  this.initialized_ = false;
+  this.accessToken_ = null;
+};
+
+/**
+ * Initializes the web view by installing hooks injecting the authorization
+ * headers.
+ * @param {function()} callback Completion callback.
+ */
+ShareDialog.WebViewAuthorizer.prototype.initialize = function(callback) {
+  if (this.initialized_) {
+    callback();
+    return;
+  }
+
+  var registerInjectionHooks = function() {
+    this.webView_.removeEventListener('loadstop', registerInjectionHooks);
+    this.webView_.onBeforeSendHeaders.addListener(
+      this.authorizeRequest_.bind(this),
+      {urls: [this.origin_ + '/*']},
+      ['blocking', 'requestHeaders']);
+    this.initialized_ = true;
+    callback();
+  }.bind(this);
+
+  this.webView_.addEventListener('loadstop', registerInjectionHooks);
+  this.webView_.setAttribute('src', 'data:text/html,');
+};
+
+/**
+ * Authorizes the web view by fetching the freshest access tokens.
+ * @param {function()} callback Completion callback.
+ */
+ShareDialog.WebViewAuthorizer.prototype.authorize = function(callback) {
+  // Fetch or update the access token.
+  chrome.fileBrowserPrivate.requestAccessToken(false,  // force_refresh
+      function(inAccessToken) {
+        this.accessToken_ = inAccessToken;
+        callback();
+      }.bind(this));
+};
+
+/**
+ * Injects headers into the passed request.
+ * @param {Event} e Request event.
+ * @return {{requestHeaders: HttpHeaders}} Modified headers.
+ * @private
+ */
+ShareDialog.WebViewAuthorizer.prototype.authorizeRequest_ = function(e) {
+  e.requestHeaders.push({
+    name: 'Authorization',
+    value: 'Bearer ' + this.accessToken_
+  });
+  return {requestHeaders: e.requestHeaders};
+};
+
+ShareDialog.prototype = {
+  __proto__: cr.ui.dialogs.BaseDialog.prototype
+};
+
+/**
+ * One-time initialization of DOM.
+ * @private
+ */
+ShareDialog.prototype.initDom_ = function() {
+  cr.ui.dialogs.BaseDialog.prototype.initDom_.call(this);
+  this.frame_.classList.add('share-dialog-frame');
+
+  this.spinnerWrapper_ = this.document_.createElement('div');
+  this.spinnerWrapper_.className = 'spinner-container';
+  this.frame_.appendChild(this.spinnerWrapper_);
+
+  this.spinner_ = this.document_.createElement('div');
+  this.spinner_.className = 'spinner';
+  this.spinnerWrapper_.appendChild(this.spinner_);
+
+  this.webViewWrapper_ = this.document_.createElement('div');
+  this.webViewWrapper_.className = 'share-dialog-webview-wrapper';
+  this.cancelButton_.hidden = true;
+  this.okButton_.hidden = true;
+  this.frame_.insertBefore(this.webViewWrapper_,
+                           this.frame_.querySelector('.cr-dialog-buttons'));
+};
+
+/**
+ * @override
+ */
+ShareDialog.prototype.onResized = function(width, height, callback) {
+  if (width && height) {
+    this.webViewWrapper_.style.width = width + 'px';
+    this.webViewWrapper_.style.height = height + 'px';
+    this.webView_.style.width = width + 'px';
+    this.webView_.style.height = height + 'px';
+  }
+  setTimeout(callback, 0);
+};
+
+/**
+ * @override
+ */
+ShareDialog.prototype.onClosed = function() {
+  this.hide();
+};
+
+/**
+ * @override
+ */
+ShareDialog.prototype.onLoaded = function() {
+  if (this.failureTimeout_) {
+    clearTimeout(this.failureTimeout_);
+    this.failureTimeout_ = null;
+  }
+
+  this.okButton_.hidden = false;
+  this.spinnerWrapper_.hidden = true;
+  this.webViewWrapper_.classList.add('loaded');
+  this.webView_.focus();
+};
+
+/**
+ * @override
+ */
+ShareDialog.prototype.onLoadFailed = function() {
+  this.hide();
+  setTimeout(this.onFailure_.bind(this),
+             cr.ui.dialogs.BaseDialog.ANIMATE_STABLE_DURATION);
+};
+
+/**
+ * @override
+ */
+ShareDialog.prototype.hide = function() {
+  if (this.shareClient_) {
+    this.shareClient_.dispose();
+    this.shareClient_ = null;
+  }
+  this.webViewWrapper_.textContent = '';
+  this.onQueueTaskFinished_();
+  this.onQueueTaskFinished_ = null;
+  if (this.failureTimeout_) {
+    clearTimeout(this.failureTimeout_);
+    this.failureTimeout_ = null;
+  }
+  cr.ui.dialogs.BaseDialog.prototype.hide.call(this);
+};
+
+/**
+ * Shows the dialog.
+ * @param {FileEntry} entry Entry to share.
+ * @param {function()} onFailure Failure callback.
+ */
+ShareDialog.prototype.show = function(entry, onFailure) {
+  this.queue_.run(function(callback) {
+    this.onQueueTaskFinished_ = callback;
+    this.onFailure_ = onFailure;
+    this.spinnerWrapper_.hidden = false;
+    this.webViewWrapper_.style.width = '';
+    this.webViewWrapper_.style.height = '';
+
+    var onError = function() {
+      onFailure();
+      this.hide();
+    }.bind(this);
+
+    // If the embedded share dialog is not started within some time, then
+    // give up and show an error message.
+    this.failureTimeout_ = setTimeout(function() {
+      onError();
+    }, ShareDialog.FAILURE_TIMEOUT);
+
+    // TODO(mtomasz): Move to initDom_() once and reuse <webview> once it gets
+    // fixed. See: crbug.com/260622.
+    this.webView_ = util.createChild(
+        this.webViewWrapper_, 'share-dialog-webview', 'webview');
+    this.webView_.setAttribute('tabIndex', '-1');
+    this.webViewAuthorizer_ = new ShareDialog.WebViewAuthorizer(
+        ShareClient.SHARE_TARGET, this.webView_);
+
+    cr.ui.dialogs.BaseDialog.prototype.show.call(this, '', null, null, null);
+
+    // Initialize and authorize the Web View tag asynchronously.
+    var group = new AsyncUtil.Group();
+    group.add(this.webViewAuthorizer_.initialize.bind(this.webViewAuthorizer_));
+    group.add(this.webViewAuthorizer_.authorize.bind(this.webViewAuthorizer_));
+
+    group.run(function() {
+      // Loads the metadata and later the share widget.
+      this.metadataCache_.get(entry, 'drive', function(metadata) {
+        if (!metadata.shareUrl) {
+          onError();
+          return;
+        }
+        var shareUrl = metadata.shareUrl + '&embedOrigin=' +
+            ShareClient.SHARE_ORIGIN;
+        this.shareClient_ = new ShareClient(this.webView_,
+                                            shareUrl,
+                                            this);
+        this.shareClient_.load();
+      }.bind(this));
+    }.bind(this));
+  }.bind(this));
+};
diff --git a/chrome/browser/resources/file_manager/js/util.js b/chrome/browser/resources/file_manager/js/util.js
index 59ce54e..c5c909d 100644
--- a/chrome/browser/resources/file_manager/js/util.js
+++ b/chrome/browser/resources/file_manager/js/util.js
@@ -456,6 +456,72 @@
 };
 
 /**
+ * Checks if an entry exists at |relativePath| in |dirEntry|.
+ * If exists, tries to deduplicate the path by inserting parenthesized number,
+ * such as " (1)", before the extension. If it still exists, tries the
+ * deduplication again by increasing the number up to 10 times.
+ * For example, suppose "file.txt" is given, "file.txt", "file (1).txt",
+ * "file (2).txt", ..., "file (9).txt" will be tried.
+ *
+ * @param {DirectoryEntry} dirEntry The target directory entry.
+ * @param {string} relativePath The path to be deduplicated.
+ * @param {function(string)} onSuccess Called with the deduplicated path on
+ *     success.
+ * @param {function(string,Entry|FileError)} onError Called on error.
+ */
+util.deduplicatePath = function(dirEntry, relativePath, onSuccess, onError) {
+  // The trial is up to 10.
+  var MAX_RETRY = 10;
+
+  // Crack the path into three part. The parenthesized number (if exists) will
+  // be replaced by incremented number for retry. For example, suppose
+  // |relativePath| is "file (10).txt", the second check path will be
+  // "file (11).txt".
+  var match = /^(.*?)(?: \((\d+)\))?(\.[^.]*?)?$/.exec(relativePath);
+  var prefix = match[1];
+  var copyNumber = match[2] ? parseInt(match[2], 10) : 0;
+  var ext = match[3] ? match[3] : '';
+
+  // The path currently checking the existence.
+  var trialPath = relativePath;
+
+  var onNotResolved = function(err) {
+    // We expect to be unable to resolve the target file, since we're going
+    // to create it during the copy.  However, if the resolve fails with
+    // anything other than NOT_FOUND, that's trouble.
+    if (err.code != FileError.NOT_FOUND_ERR) {
+      onError('FILESYSTEM_ERROR', err);
+      return;
+    }
+
+    // Found a path that doesn't exist.
+    onSuccess(trialPath);
+  }
+
+  // Remember the first existing entry for error.
+  var firstExistingEntry = null;
+  var numRetry = MAX_RETRY;
+
+  var onResolved = function(entry) {
+    if (!firstExistingEntry)
+      firstExistingEntry = entry;
+
+    if (--numRetry == 0) {
+      // Hit the limit of the number of retrial.
+      onError('TARGET_EXISTS', firstExistingEntry);
+      return;
+    }
+
+    ++copyNumber;
+    trialPath = prefix + ' (' + copyNumber + ')' + ext;
+    util.resolvePath(dirEntry, trialPath, onResolved, onNotResolved);
+  };
+
+  // Check to see if the target exists.
+  util.resolvePath(dirEntry, trialPath, onResolved, onNotResolved);
+};
+
+/**
  * Convert a number of bytes into a human friendly format, using the correct
  * number separators.
  *
diff --git a/chrome/browser/resources/file_manager/js/volume_list.js b/chrome/browser/resources/file_manager/js/volume_list.js
index bb77526..a0e55f3 100644
--- a/chrome/browser/resources/file_manager/js/volume_list.js
+++ b/chrome/browser/resources/file_manager/js/volume_list.js
@@ -8,6 +8,8 @@
  * A volume list model. This model combines the 2 lists.
  * @param {cr.ui.ArrayDataModel} volumesList The first list of the model.
  * @param {cr.ui.ArrayDataModel} pinnedList The second list of the model.
+ * @constructor
+ * @extends {cr.EventTarget}
  */
 function VolumeListModel(volumesList, pinnedList) {
   this.volumesList_ = volumesList;
@@ -55,28 +57,8 @@
   this.volumesList_.addEventListener('change', changeHandler.bind(this, 1));
   this.pinnedList_.addEventListener('change', changeHandler.bind(this, 2));
 
-  // Generates a combined 'splice' event from an event of either list.
-  var spliceHandler = function(listNum, e) {
-    var spliceEvent = new Event('splice');
-    spliceEvent.index =
-        (listNum == 1) ? e.index : (e.index + this.volumesList_.length);
-
-    // spliceEvent.removed, spliceEvent.add are not supported yet.
-    spliceEvent.removed = null;
-    spliceEvent.add = null;
-
-    this.dispatchEvent(spliceEvent);
-  };
-  this.volumesList_.addEventListener('splice', spliceHandler.bind(this, 1));
-  this.pinnedList_.addEventListener('splice', spliceHandler.bind(this, 2));
-
-  // Generates a combined 'sorted' event from an event of either list.
-  var sortedHandler = function(listNum, e) {
-    var sortedEvent = new Event('sorted');
-    this.dispatchEvent(sortedEvent);
-  }
-  this.volumesList_.addEventListener('sorted', sortedHandler.bind(this, 1));
-  this.pinnedList_.addEventListener('sorted', sortedHandler.bind(this, 2));
+  // 'splice' and 'sorted' events are not implemented, since they are not used
+  // in list.js.
 }
 
 /**
diff --git a/chrome/browser/resources/file_manager/main.html b/chrome/browser/resources/file_manager/main.html
index 6392051..91ac96d 100644
--- a/chrome/browser/resources/file_manager/main.html
+++ b/chrome/browser/resources/file_manager/main.html
@@ -101,7 +101,10 @@
       <script src="js/file_tasks.js"></script>
       <script src="js/file_transfer_controller.js"></script>
       <script src="js/file_type.js"></script>
+      <script src="js/folder_shortcuts_data_model.js"></script>
       <script src="js/scrollbar.js"></script>
+      <script src="js/share_client.js"></script>
+      <script src="js/share_dialog.js"></script>
       <script src="js/tree.css.js"></script>
       <script src="js/volume_manager.js"></script>
       <script src="js/volume_list.js"></script>
diff --git a/chrome/browser/resources/file_manager/manifest.json b/chrome/browser/resources/file_manager/manifest.json
index 32bbcf8..503bce9 100644
--- a/chrome/browser/resources/file_manager/manifest.json
+++ b/chrome/browser/resources/file_manager/manifest.json
@@ -27,6 +27,7 @@
     "metricsPrivate",
     "commandLinePrivate",
     "unlimitedStorage",
+    "webview",
     // Comment out chrome:// permissions to debug on a desktop browser.
     "chrome://extension-icon/",
     "chrome://resources/",
@@ -229,6 +230,6 @@
         "js/background.js"]
     },
     // chrome-extension://pmfjbimdmchhbnneeidfognadeopoehp is the image loader extension.
-    "content_security_policy": "default-src 'none'; script-src 'self' chrome://resources chrome-extension://pmfjbimdmchhbnneeidfognadeopoehp; style-src 'self' 'unsafe-inline' chrome://resources; 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"
+    "content_security_policy": "default-src 'none'; script-src 'self' chrome://resources chrome-extension://pmfjbimdmchhbnneeidfognadeopoehp; style-src 'self' 'unsafe-inline' chrome://resources; 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; object-src 'self'"
   }
 }
diff --git a/chrome/browser/resources/gesture_config.css b/chrome/browser/resources/gesture_config.css
index 74f6a6f..eec68a9 100644
--- a/chrome/browser/resources/gesture_config.css
+++ b/chrome/browser/resources/gesture_config.css
@@ -8,7 +8,8 @@
 }
 
 form {
-  width: 700px;
+  display: table;
+  margin: 8px;
 }
 
 h2 {
@@ -17,11 +18,13 @@
 }
 
 .buttons-pane {
-  width: 90%;
+  display: inline-block;
+  width: 100%;
 }
 
 #reset-all-button {
   float: right;
+  min-width: 15em;
 }
 
 html[dir=rtl] #reset-all-button {
diff --git a/chrome/browser/resources/gesture_config.html b/chrome/browser/resources/gesture_config.html
index 34a7215..c478bb0 100644
--- a/chrome/browser/resources/gesture_config.html
+++ b/chrome/browser/resources/gesture_config.html
@@ -10,10 +10,10 @@
 </head>
 <body>
 <form>
-  <div id="gesture-form"></div>
   <div class="buttons-pane">
     <button id="reset-all-button">Reset All</button>
   </div>
+  <div id="gesture-form"></div>
 </form>
 <div id="section-template">
   <h2 class="section-title"></h2>
diff --git a/chrome/browser/resources/gesture_config.js b/chrome/browser/resources/gesture_config.js
index 062cdca..e38baa9 100644
--- a/chrome/browser/resources/gesture_config.js
+++ b/chrome/browser/resources/gesture_config.js
@@ -85,6 +85,7 @@
       $(field.key).onchange = (function(key) {
         config.setPreferenceValue(key, $(key).value);
         gesture_config.updateResetButton($(key + '-reset'), false);
+        gesture_config.updateResetAllButton(false);
       }).bind(null, field.key);
       $(field.key + '-reset').onclick = (function(key) {
         config.resetPreferenceValue(key);
@@ -532,12 +533,26 @@
     };
   },
 
-/**
- * Updates the status and label of a preference reset button.
- * @param {HTMLInputElement} resetButton Reset button for the preference.
- * @param {boolean} isDefault Whether the preference is set to the default
- *     value.
- */
+  /**
+   * Checks if all gesture preferences are set to default by checking the status
+   * of the reset button associated with each preference.
+   * @return {boolean} True if all gesture preferences are set to default.
+   */
+  areAllPrefsSetToDefault: function() {
+    var resets = $('gesture-form').querySelectorAll('.row-reset');
+    for (var i = 0; i < resets.length; i++) {
+      if (!resets[i].disabled)
+        return false;
+    }
+    return true;
+  },
+
+  /**
+   * Updates the status and label of a preference reset button.
+   * @param {HTMLInputElement} resetButton Reset button for the preference.
+   * @param {boolean} isDefault Whether the preference is set to the default
+   *     value.
+   */
   updateResetButton: function(resetButton, isDefault) {
     /** @const */ var TITLE_DEFAULT = 'Default';
 
@@ -548,6 +563,21 @@
   },
 
   /**
+   * Updates the status and label of "Reset All" button.
+   * @param {boolean} isDefault Whether all preference are set to their default
+   *     values.
+   */
+  updateResetAllButton: function(isDefault) {
+    /** @const */ var TITLE_DEFAULT = 'Everything is set to default';
+
+    /** @const */ var TITLE_NOT_DEFAULT = 'Reset All To Default';
+
+    var button = $('reset-all-button');
+    button.innerHTML = isDefault ? TITLE_DEFAULT : TITLE_NOT_DEFAULT;
+    button.disabled = isDefault;
+  },
+
+  /**
    * Handle callback from call to updatePreferenceValue.
    * @param {string} prefName The name of the requested preference value.
    * @param {value} value The current value associated with prefName.
@@ -557,6 +587,7 @@
     prefName = prefName.substring(prefName.indexOf('.') + 1);
     $(prefName).value = value;
     this.updateResetButton($(prefName + '-reset'), isDefault);
+    this.updateResetAllButton(this.areAllPrefsSetToDefault());
   },
 };
 
diff --git a/chrome/browser/resources/google_now/background.js b/chrome/browser/resources/google_now/background.js
index e651a18..534ff65 100644
--- a/chrome/browser/resources/google_now/background.js
+++ b/chrome/browser/resources/google_now/background.js
@@ -32,8 +32,10 @@
  */
 var HTTP_OK = 200;
 
+var HTTP_BAD_REQUEST = 400;
 var HTTP_UNAUTHORIZED = 401;
 var HTTP_FORBIDDEN = 403;
+var HTTP_METHOD_NOT_ALLOWED = 405;
 
 /**
  * Initial period for polling for Google Now Notifications cards to use when the
@@ -58,6 +60,11 @@
 var MAXIMUM_RETRY_DISMISS_PERIOD_SECONDS = 60 * 60;  // 1 hour
 
 /**
+ * Time we keep retrying dismissals.
+ */
+var MAXIMUM_DISMISSAL_AGE_MS = 24 * 60 * 60 * 1000; // 1 day
+
+/**
  * Time we keep dismissals after successful server dismiss requests.
  */
 var DISMISS_RETENTION_TIME_MS = 20 * 60 * 1000;  // 20 minutes
@@ -274,7 +281,8 @@
 
   notificationsData[card.notificationId] = {
     actionUrls: card.actionUrls,
-    version: card.version
+    version: card.version,
+    dismissalParameters: card.dismissal
   };
 }
 
@@ -405,7 +413,8 @@
       ',' + position.coords.longitude +
       ',' + position.coords.accuracy;
 
-  var request = buildServerRequest('notifications');
+  var request = buildServerRequest('notifications',
+                                   'application/x-www-form-urlencoded');
 
   request.onloadend = function(event) {
     console.log('requestNotificationCards-onloadend ' + request.status);
@@ -466,30 +475,47 @@
  * @param {string} notificationId Unique identifier of the card.
  * @param {number} dismissalTimeMs Time of the user's dismissal of the card in
  *     milliseconds since epoch.
- * @param {function(boolean)} callbackBoolean Completion callback with 'success'
+ * @param {Object} dismissalParameters Dismissal parameters.
+ * @param {function(boolean)} callbackBoolean Completion callback with 'done'
  *     parameter.
  */
 function requestCardDismissal(
-    notificationId, dismissalTimeMs, callbackBoolean) {
+    notificationId, dismissalTimeMs, dismissalParameters, callbackBoolean) {
   console.log('requestDismissingCard ' + notificationId + ' from ' +
       NOTIFICATION_CARDS_URL);
+
+  var dismissalAge = Date.now() - dismissalTimeMs;
+
+  if (dismissalAge > MAXIMUM_DISMISSAL_AGE_MS) {
+    callbackBoolean(true);
+    return;
+  }
+
   recordEvent(DiagnosticEvent.DISMISS_REQUEST_TOTAL);
-  // Send a dismiss request to the server.
-  var requestParameters = 'id=' + notificationId +
-                          '&dismissalAge=' + (Date.now() - dismissalTimeMs);
-  var request = buildServerRequest('dismiss');
+  var request = buildServerRequest('dismiss', 'application/json');
   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);
+    // A dismissal doesn't require further retries if it was successful or
+    // doesn't have a chance for successful completion.
+    var done = request.status == HTTP_OK ||
+        request.status == HTTP_BAD_REQUEST ||
+        request.status == HTTP_METHOD_NOT_ALLOWED;
+    callbackBoolean(done);
   };
 
   setAuthorization(request, function(success) {
     if (success) {
       tasks.debugSetStepName('requestCardDismissal-send-request');
-      request.send(requestParameters);
+
+      var dismissalObject = {
+        id: notificationId,
+        age: dismissalAge,
+        dismissal: dismissalParameters
+      };
+      request.send(JSON.stringify(dismissalObject));
     } else {
       callbackBoolean(false);
     }
@@ -532,16 +558,19 @@
       // recursively with the rest.
       var dismissal = items.pendingDismissals[0];
       requestCardDismissal(
-          dismissal.notificationId, dismissal.time, function(success) {
-        if (success) {
-          dismissalsChanged = true;
-          items.pendingDismissals.splice(0, 1);
-          items.recentDismissals[dismissal.notificationId] = Date.now();
-          doProcessDismissals();
-        } else {
-          onFinish(false);
-        }
-      });
+          dismissal.notificationId,
+          dismissal.time,
+          dismissal.parameters,
+          function(done) {
+            if (done) {
+              dismissalsChanged = true;
+              items.pendingDismissals.splice(0, 1);
+              items.recentDismissals[dismissal.notificationId] = Date.now();
+              doProcessDismissals();
+            } else {
+              onFinish(false);
+            }
+          });
     }
 
     doProcessDismissals();
@@ -645,13 +674,17 @@
         notificationId,
         function() {});
 
-    tasks.debugSetStepName('onNotificationClosed-get-pendingDismissals');
-    storage.get('pendingDismissals', function(items) {
+    tasks.debugSetStepName('onNotificationClosed-storage-get');
+    storage.get(['pendingDismissals', 'notificationsData'], function(items) {
       items.pendingDismissals = items.pendingDismissals || [];
+      items.notificationsData = items.notificationsData || {};
+
+      var notificationData = items.notificationsData[notificationId];
 
       var dismissal = {
         notificationId: notificationId,
-        time: Date.now()
+        time: Date.now(),
+        parameters: notificationData && notificationData.dismissalParameters
       };
       items.pendingDismissals.push(dismissal);
       storage.set({pendingDismissals: items.pendingDismissals});
diff --git a/chrome/browser/resources/google_now/utility.js b/chrome/browser/resources/google_now/utility.js
index 9405bde..eb8f5cc 100644
--- a/chrome/browser/resources/google_now/utility.js
+++ b/chrome/browser/resources/google_now/utility.js
@@ -32,14 +32,15 @@
 /**
  * Builds a request to the notification server.
  * @param {string} handlerName Server handler to send the request to.
+ * @param {string} contentType Value for the Content-type header.
  * @return {XMLHttpRequest} Server request.
  */
-function buildServerRequest(handlerName) {
+function buildServerRequest(handlerName, contentType) {
   var request = new XMLHttpRequest();
 
   request.responseType = 'text';
   request.open('POST', NOTIFICATION_CARDS_URL + '/' + handlerName, true);
-  request.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
+  request.setRequestHeader('Content-type', contentType);
 
   return request;
 }
@@ -177,7 +178,8 @@
         '&script=' + encodeURIComponent(file) +
         '&line=' + encodeURIComponent(line) +
         '&trace=' + encodeURIComponent(filteredStack);
-    var request = buildServerRequest('jserror');
+    var request = buildServerRequest('jserror',
+                                     'application/x-www-form-urlencoded');
     request.onloadend = function(event) {
       console.log('sendErrorReport status: ' + request.status);
     };
diff --git a/chrome/browser/resources/history/history.js b/chrome/browser/resources/history/history.js
index 3408a74..d5a8ef8 100644
--- a/chrome/browser/resources/history/history.js
+++ b/chrome/browser/resources/history/history.js
@@ -162,6 +162,7 @@
     // Clicking anywhere in the entryBox will check/uncheck the checkbox.
     entryBox.setAttribute('for', checkbox.id);
     entryBox.addEventListener('mousedown', entryBoxMousedown);
+    entryBox.addEventListener('click', entryBoxClick);
   }
 
   // Keep track of the drop down that triggered the menu, so we know
@@ -489,17 +490,17 @@
  * @param {Array} results A list of results.
  */
 HistoryModel.prototype.addResults = function(info, results) {
+  // If no requests are in flight then this was an old request so we drop the
+  // results. Double check the search term as well.
+  if (!this.inFlight_ || info.term != this.searchText_)
+    return;
+
   $('loading-spinner').hidden = true;
   this.inFlight_ = false;
   this.isQueryFinished_ = info.finished;
   this.queryStartTime = info.queryStartTime;
   this.queryEndTime = info.queryEndTime;
 
-  // If the results are not for the current search term then there is nothing
-  // more to do.
-  if (info.term != this.searchText_)
-    return;
-
   var lastVisit = this.visits_.slice(-1)[0];
   var lastDay = lastVisit ? lastVisit.dateRelativeDay : null;
 
@@ -1693,11 +1694,20 @@
  * @param {Event} e The click event.
  */
 function checkboxClicked(e) {
-  var checkbox = e.currentTarget;
+  handleCheckboxStateChange(e.currentTarget, e.shiftKey);
+}
+
+/**
+ * Post-process of checkbox state change. This handles range selection and
+ * updates internal state.
+ * @param {!HTMLInputElement} checkbox Clicked checkbox.
+ * @param {boolean} shiftKey true if shift key is pressed.
+ */
+function handleCheckboxStateChange(checkbox, shiftKey) {
   updateParentCheckbox(checkbox);
   var id = Number(checkbox.id.slice('checkbox-'.length));
   // Handle multi-select if shift was pressed.
-  if (event.shiftKey && (selectionAnchor != -1)) {
+  if (shiftKey && (selectionAnchor != -1)) {
     var checked = checkbox.checked;
     // Set all checkboxes from the anchor up to the clicked checkbox to the
     // state of the clicked one.
@@ -1753,9 +1763,23 @@
 
 function entryBoxMousedown(event) {
   // Prevent text selection when shift-clicking to select multiple entries.
-  if (event.shiftKey) {
+  if (event.shiftKey)
     event.preventDefault();
-  }
+}
+
+/**
+ * Handle click event for entryBox labels.
+ * @param {!MouseEvent} event A click event.
+ */
+function entryBoxClick(event) {
+  var tagName = event.target.tagName;
+  if (tagName == 'BUTTON' || tagName == 'INPUT' || tagName == 'A')
+    return;
+  var checkbox = event.currentTarget.control;
+  checkbox.checked = !checkbox.checked;
+  handleCheckboxStateChange(checkbox, event.shiftKey);
+  // We don't want to focus on the checkbox.
+  event.preventDefault();
 }
 
 // This is pulled out so we can wait for it in tests.
@@ -1763,12 +1787,20 @@
   node.parentNode.removeChild(node);
 }
 
-function removeNode(node) {
+/**
+ * Triggers a fade-out animation, and then removes |node| from the DOM.
+ * @param {Node} node The node to be removed.
+ * @param {Function?} onRemove A function to be called after the node
+ *     has been removed from the DOM.
+ */
+function removeNode(node, onRemove) {
   node.classList.add('fade-out'); // Trigger CSS fade out animation.
 
   // Delete the node when the animation is complete.
   node.addEventListener('webkitTransitionEnd', function() {
     removeNodeWithoutTransition(node);
+    if (onRemove)
+      onRemove();
   });
 }
 
@@ -1781,17 +1813,17 @@
   var nextEntry = entry.nextSibling;
   var previousEntry = entry.previousSibling;
 
-  removeNode(entry);
+  removeNode(entry, function() {
+    historyView.updateSelectionEditButtons();
+  });
 
   // if there is no previous entry, and the next entry is a gap, remove it
-  if (!previousEntry && nextEntry && nextEntry.className == 'gap') {
+  if (!previousEntry && nextEntry && nextEntry.className == 'gap')
     removeNode(nextEntry);
-  }
 
   // if there is no next entry, and the previous entry is a gap, remove it
-  if (!nextEntry && previousEntry && previousEntry.className == 'gap') {
+  if (!nextEntry && previousEntry && previousEntry.className == 'gap')
     removeNode(previousEntry);
-  }
 
   // if both the next and previous entries are gaps, remove one
   if (nextEntry && nextEntry.className == 'gap' &&
diff --git a/chrome/browser/resources/inspect/inspect.css b/chrome/browser/resources/inspect/inspect.css
index e6bcfd0..1d5bc7d 100644
--- a/chrome/browser/resources/inspect/inspect.css
+++ b/chrome/browser/resources/inspect/inspect.css
@@ -7,34 +7,87 @@
 body {
   color: rgb(48, 57, 66);
   font-family: Arial, sans-serif;
-  font-size: 12px;
-  margin: 20px;
+  font-size: 13px;
+  margin: 0;
   min-width: 47em;
-  padding-bottom: 65px;
+  padding: 20px 20px 65px 0;
 }
 
 img {
   float: left;
   height: 16px;
+  padding-left: 2px;
   padding-right: 5px;
   width: 16px;
 }
 
-.section {
+#container {
+  -webkit-flex-direction: row;
+  display: -webkit-flex;
+}
+
+#navigation {
+  width: 150px;
+}
+
+#content {
+  -webkit-flex: 1;
+}
+
+#caption {
+  color: rgb(92, 97, 102);
+  font-size: 150%;
+  padding-bottom: 10px;
+  padding-left: 20px;
+}
+
+.tab-header {
+  -webkit-border-start: 6px solid transparent;
+  padding-left: 15px;
+}
+
+.tab-header.selected {
+  -webkit-border-start-color: rgb(78, 87, 100);
+}
+
+.tab-header > button {
+  background-color: white;
+  border: 0;
+  cursor: pointer;
+  font: inherit;
+  line-height: 17px;
+  margin: 6px 0;
+  padding: 0 2px;
+}
+
+.tab-header:not(.selected) > button {
+  color: #999;
+}
+
+#content > div:not(.selected) {
+  display: none;
+}
+
+.content-header {
   border-bottom: 1px solid #eee;
-  font-size: 1.5em;
+  font-size: 150%;
+  padding-bottom: 4px;
+}
+
+.section {
+  font-size: 150%;
   margin: 10px 0 0;
-  padding: 2px 2px;
+  padding: 2px 0;
 }
 
 .small-section {
   font-weight: bold;
   margin: 5px 0 0;
-  padding: 2px 2px;
+  padding: 2px 0;
 }
 
 .row {
-  padding: 5px;
+  padding: 5px 0;
 }
 
 .url {
diff --git a/chrome/browser/resources/inspect/inspect.html b/chrome/browser/resources/inspect/inspect.html
index 835aff9..389a7a3 100644
--- a/chrome/browser/resources/inspect/inspect.html
+++ b/chrome/browser/resources/inspect/inspect.html
@@ -16,24 +16,32 @@
 
 <body>
 
-<div id="top">
-  <div class="section-header">
+<div id="container">
+  <div id="navigation">
+    <div id="caption">DevTools</div>
+  </div>
+  <div id="content">
+    <div id="devices-tab">
+      <div class="content-header">Devices</div>
+      <div id="devices"></div>
+    </div>
+    <div id="pages-tab">
+      <div class="content-header">Pages</div>
+      <div id="pages" class="list"></div>
+    </div>
+    <div id="extensions-tab">
+      <div class="content-header">Extensions</div>
+      <div id="extensions" class="list"></div>
+    </div>
+    <div id="workers-tab">
+      <div class="content-header">Shared workers</div>
+      <div id="workers" class="list"></div>
+    </div>
+    <div id="other-tab">
+      <div class="content-header">Other</div>
+      <div id="others" class="list"></div>
+    </div>
   </div>
 </div>
-
-<div id="devices"></div>
-
-<div class="section">Pages</div>
-<div id="pages" class="list"></div>
-
-<div class="section">Extensions</div>
-<div id="extensions" class="list"></div>
-
-<div class="section">Shared workers</div>
-<div id="workers" class="list"></div>
-
-<div class="section">Other</div>
-<div id="others" class="list"></div>
-
 </body>
 </html>
diff --git a/chrome/browser/resources/inspect/inspect.js b/chrome/browser/resources/inspect/inspect.js
index 3344e14..819272b 100644
--- a/chrome/browser/resources/inspect/inspect.js
+++ b/chrome/browser/resources/inspect/inspect.js
@@ -25,9 +25,39 @@
 }
 
 function onload() {
+  var tabContents = document.querySelectorAll('#content > div');
+  for (var i = 0; i != tabContents.length; i++) {
+    var tabContent = tabContents[i];
+    var tabName = tabContent.querySelector('.content-header').textContent;
+
+    var tabHeader = document.createElement('div');
+    tabHeader.className = 'tab-header';
+    var button = document.createElement('button');
+    button.textContent = tabName;
+    tabHeader.appendChild(button);
+    tabHeader.addEventListener('click', selectTab.bind(null, tabContent.id));
+    $('navigation').appendChild(tabHeader);
+  }
+  selectTab('devices-tab');
   populateLists();
 }
 
+function selectTab(id) {
+  var tabContents = document.querySelectorAll('#content > div');
+  var tabHeaders = $('navigation').querySelectorAll('.tab-header');
+  for (var i = 0; i != tabContents.length; i++) {
+    var tabContent = tabContents[i];
+    var tabHeader = tabHeaders[i];
+    if (tabContent.id == id) {
+      tabContent.classList.add('selected');
+      tabHeader.classList.add('selected');
+    } else {
+      tabContent.classList.remove('selected');
+      tabHeader.classList.remove('selected');
+    }
+  }
+}
+
 function populateLists() {
   var data = requestData();
 
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
deleted file mode 100644
index ec5e4ba..0000000
--- a/chrome/browser/resources/local_omnibox_popup/images/2x/history_icon.png
+++ /dev/null
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
deleted file mode 100644
index a7cf3cc..0000000
--- a/chrome/browser/resources/local_omnibox_popup/images/2x/page_icon.png
+++ /dev/null
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
deleted file mode 100644
index ac74fd7..0000000
--- a/chrome/browser/resources/local_omnibox_popup/images/2x/search_icon.png
+++ /dev/null
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
deleted file mode 100644
index 6e7f731..0000000
--- a/chrome/browser/resources/local_omnibox_popup/images/history_icon.png
+++ /dev/null
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
deleted file mode 100644
index b782547..0000000
--- a/chrome/browser/resources/local_omnibox_popup/images/page_icon.png
+++ /dev/null
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
deleted file mode 100644
index ed89c7b..0000000
--- a/chrome/browser/resources/local_omnibox_popup/images/search_icon.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/ntp_android/ntp_android.js b/chrome/browser/resources/ntp_android/ntp_android.js
index e276677..9ec3a10 100644
--- a/chrome/browser/resources/ntp_android/ntp_android.js
+++ b/chrome/browser/resources/ntp_android/ntp_android.js
@@ -535,6 +535,7 @@
    *     reopen a tab.
    */
   function openRecentlyClosedTab(item, evt) {
+    chrome.send('openedRecentlyClosed');
     chrome.send('reopenTab', [item.sessionId]);
   }
 
@@ -946,7 +947,7 @@
       return;
 
     var clickFunction = function(item) {
-      chrome.send('metricsHandler:recordAction', ['MobileNTPMostVisited']);
+      chrome.send('openedMostVisited');
       window.location = item.url;
     };
     populateData(findList('most_visited'), SectionType.MOST_VISITED, data,
@@ -1018,7 +1019,7 @@
         if (item['folder']) {
           browseToBookmarkFolder(item.id);
         } else if (!!item.url) {
-          chrome.send('metricsHandler:recordAction', ['MobileNTPBookmark']);
+          chrome.send('openedBookmark');
           window.location = item.url;
         }
       };
@@ -1195,6 +1196,25 @@
    *     when chrome.send('showContextMenu') was called.
    */
   function onCustomMenuSelected(itemId) {
+    if (contextMenuUrl != null) {
+      switch (itemId) {
+        case ContextMenuItemIds.BOOKMARK_OPEN_IN_NEW_TAB:
+        case ContextMenuItemIds.BOOKMARK_OPEN_IN_INCOGNITO_TAB:
+          chrome.send('openedBookmark');
+          break;
+
+        case ContextMenuItemIds.MOST_VISITED_OPEN_IN_NEW_TAB:
+        case ContextMenuItemIds.MOST_VISITED_OPEN_IN_INCOGNITO_TAB:
+          chrome.send('openedMostVisited');
+          break;
+
+        case ContextMenuItemIds.RECENTLY_CLOSED_OPEN_IN_NEW_TAB:
+        case ContextMenuItemIds.RECENTLY_CLOSED_OPEN_IN_INCOGNITO_TAB:
+          chrome.send('openedRecentlyClosed');
+          break;
+      }
+    }
+
     switch (itemId) {
       case ContextMenuItemIds.BOOKMARK_OPEN_IN_NEW_TAB:
       case ContextMenuItemIds.MOST_VISITED_OPEN_IN_NEW_TAB:
@@ -1835,7 +1855,7 @@
           metaKeyPressed = evt.metaKey;
           shiftKeyPressed = evt.shiftKey;
         }
-        chrome.send('metricsHandler:recordAction', ['MobileNTPForeignSession']);
+        chrome.send('openedForeignSession');
         chrome.send('openForeignSession', [String(item.sessionTag),
             String(item.winNum), String(item.sessionId), buttonIndex,
             altKeyPressed, ctrlKeyPressed, metaKeyPressed, shiftKeyPressed]);
diff --git a/chrome/browser/resources/omnibox/omnibox.js b/chrome/browser/resources/omnibox/omnibox.js
index fd327fa..8292cf7 100644
--- a/chrome/browser/resources/omnibox/omnibox.js
+++ b/chrome/browser/resources/omnibox/omnibox.js
@@ -126,8 +126,9 @@
     new PresentationInfoRecord('Fill Into Edit', '', 'fill_into_edit', false,
         'The text shown in the omnibox when the result is selected.'),
     new PresentationInfoRecord(
-        'IAO', '', 'inline_autocomplete_offset', false,
-        'The Inline Autocomplete Offset.'),
+        'Inline Autocompletion', '', 'inline_autocompletion', false,
+        'The text shown in the omnibox as a blue highlight selection ' +
+        'following the cursor, if this match is shown inline.'),
     new PresentationInfoRecord('Del', '', 'deletable', false,
         'A green checkmark indicates that the results can be deleted from ' +
         'the visit history.'),
diff --git a/chrome/browser/resources/options/browser_options.js b/chrome/browser/resources/options/browser_options.js
index ca5e832..f221e88 100644
--- a/chrome/browser/resources/options/browser_options.js
+++ b/chrome/browser/resources/options/browser_options.js
@@ -29,13 +29,6 @@
     signedIn_: false,
 
     /**
-     * Keeps track of whether the user has completed sync setup or not.
-     * @type {boolean}
-     * @private
-     */
-    setupCompleted_: false,
-
-    /**
      * Keeps track of whether |onShowHomeButtonChanged_| has been called. See
      * |onShowHomeButtonChanged_|.
      * @type {boolean}
@@ -722,16 +715,15 @@
         $('sync-status').hidden = true;
         return;
       }
-      // If the user gets signed out or if sync gets disabled while the advanced
-      // sync settings dialog is visible, say, due to a dashboard clear, close
-      // the dialog.
-      if ((this.signedIn_ && !syncData.signedIn) ||
-          (this.setupCompleted_ && !syncData.setupCompleted)) {
+
+      // If the user gets signed out while the advanced sync settings dialog is
+      // visible, say, due to a dashboard clear, close the dialog.
+      // Note: SyncSetupOverlay.closeOverlay is a no-op if the overlay is
+      // already hidden.
+      if (this.signedIn_ && !syncData.signedIn)
         SyncSetupOverlay.closeOverlay();
-      }
 
       this.signedIn_ = syncData.signedIn;
-      this.setupCompleted_ = syncData.setupCompleted;
 
       // Display the "advanced settings" button if we're signed in and sync is
       // not managed/disabled. If the user is signed in, but sync is disabled,
diff --git a/chrome/browser/resources/options/deletable_item_list.js b/chrome/browser/resources/options/deletable_item_list.js
index 9908f0d..403dc0f 100644
--- a/chrome/browser/resources/options/deletable_item_list.js
+++ b/chrome/browser/resources/options/deletable_item_list.js
@@ -98,13 +98,16 @@
 
     /**
      * Don't let the list have a crack at the event. We don't want clicking the
-     * close button to change the selection of the list.
+     * close button to change the selection of the list or to focus on the close
+     * button.
      * @param {Event} e The mouse down/up event object.
      * @private
      */
     handleMouseDownUpOnClose_: function(e) {
-      if (!e.target.disabled)
-        e.stopPropagation();
+      if (e.target.disabled)
+        return;
+      e.stopPropagation();
+      e.preventDefault();
     },
   };
 
diff --git a/chrome/browser/resources/options/import_data_overlay.js b/chrome/browser/resources/options/import_data_overlay.js
index 9800340..ba7949c 100644
--- a/chrome/browser/resources/options/import_data_overlay.js
+++ b/chrome/browser/resources/options/import_data_overlay.js
@@ -236,6 +236,7 @@
     // Make sure that any previous import success message is hidden, and
     // we're showing the UI to import further data.
     ImportDataOverlay.getInstance().updateSuccessState_(false);
+    ImportDataOverlay.getInstance().validateCommitButton_();
 
     OptionsPage.navigateToPage('importData');
   };
diff --git a/chrome/browser/resources/options/inline_editable_list.js b/chrome/browser/resources/options/inline_editable_list.js
index 3b84302..55a38b7 100644
--- a/chrome/browser/resources/options/inline_editable_list.js
+++ b/chrome/browser/resources/options/inline_editable_list.js
@@ -95,8 +95,10 @@
      * Updates the edit state based on the current selected and lead states.
      */
     updateEditState: function() {
-      if (this.editable)
-        this.editing = this.selected && this.lead;
+      if (this.editable) {
+        this.editing = this.selected && this.lead &&
+          !this.isExtraFocusableControl(document.activeElement);
+      }
     },
 
     /**
@@ -110,9 +112,6 @@
       if (this.editing == editing)
         return;
 
-      if (this.isExtraFocusableControl(document.activeElement))
-        editing = false;
-
       if (editing)
         this.setAttribute('editing', '');
       else
@@ -343,6 +342,11 @@
         return;
 
       var clickTarget = e.target;
+      if (this.isExtraFocusableControl(clickTarget)) {
+        clickTarget.focus();
+        return;
+      }
+
       var editFields = this.editFields_;
       for (var i = 0; i < editFields.length; i++) {
         if (editFields[i] == clickTarget ||
diff --git a/chrome/browser/resources/print_preview/native_layer.js b/chrome/browser/resources/print_preview/native_layer.js
index 469c362..bda89a7 100644
--- a/chrome/browser/resources/print_preview/native_layer.js
+++ b/chrome/browser/resources/print_preview/native_layer.js
@@ -345,7 +345,7 @@
           numberFormatSymbols[1] || '.',
           unitType,
           initialSettings['previewModifiable'] || false,
-          initialSettings['initiatorTabTitle'] || '',
+          initialSettings['initiatorTitle'] || '',
           initialSettings['documentHasSelection'] || false,
           initialSettings['shouldPrintSelectionOnly'] || false,
           initialSettings['printerName'] || null,
@@ -417,7 +417,7 @@
     /**
      * Called from the C++ layer.
      * Take the PDF data handed to us and submit it to the cloud, closing the
-     * print preview tab once the upload is successful.
+     * print preview dialog once the upload is successful.
      * @param {string} data Data to send as the print job.
      * @private
      */
@@ -430,7 +430,7 @@
 
     /**
      * Called from PrintPreviewUI::OnFileSelectionCancelled to notify the print
-     * preview tab regarding the file selection cancel event.
+     * preview dialog regarding the file selection cancel event.
      * @private
      */
     onFileSelectionCancelled_: function() {
@@ -439,12 +439,12 @@
 
     /**
      * Called from PrintPreviewUI::OnFileSelectionCompleted to notify the print
-     * preview tab regarding the file selection completed event.
+     * preview dialog regarding the file selection completed event.
      * @private
      */
     onFileSelectionCompleted_: function() {
-      // If the file selection is completed and the tab is not already closed it
-      // means that a pending print to pdf request exists.
+      // If the file selection is completed and the dialog is not already closed
+      // it means that a pending print to pdf request exists.
       cr.dispatchSimpleEvent(
           this, NativeLayer.EventType.FILE_SELECTION_COMPLETE);
     },
diff --git a/chrome/browser/resources/quick_office/manifest.json b/chrome/browser/resources/quick_office/manifest.json
index e2bb7f6..ce80073 100644
--- a/chrome/browser/resources/quick_office/manifest.json
+++ b/chrome/browser/resources/quick_office/manifest.json
@@ -73,7 +73,7 @@
       "sub_package_path": "_platform_specific/arm/"
     }
   ],
-  "version": "2.9.2.35",
+  "version": "2.9.3.9",
   "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 d6de353..c8cd2f7 100644
--- a/chrome/browser/resources/quick_office/manifest_experimental.json
+++ b/chrome/browser/resources/quick_office/manifest_experimental.json
@@ -74,7 +74,7 @@
       "sub_package_path": "_platform_specific/arm/"
     }
   ],
-  "version": "2.9.2.35",
+  "version": "2.9.3.9",
   "web_accessible_resources": [
     "views/qowt.html"]
 }
diff --git a/chrome/browser/resources/user_chooser/control_bar.css b/chrome/browser/resources/user_chooser/control_bar.css
new file mode 100644
index 0000000..3eadc52
--- /dev/null
+++ b/chrome/browser/resources/user_chooser/control_bar.css
@@ -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.
+ */
+
+/* Overrides of styles in chrome/browser/resources/chromeos/login/header_bar.js
+* that are needed by the desktop user chooser screen
+*/
+#login-header-bar {
+  -webkit-padding-after: 7px;
+  bottom: 0;
+  left: 0;
+  position: absolute;
+  right: 0;
+}
+
+#login-header-bar {
+  -webkit-padding-before: 7px;
+}
+
+.header-bar-item:first-child {
+  -webkit-padding-start: 15px;
+}
+
+.header-bar-item {
+  display: inline-block;
+  height: 34px;
+}
+
+html[dir=rtl] .header-bar-item {
+  background-position: right center;
+}
+
+html[dir=rtl] #login-header-bar button {
+  background-position: right center;
+}
+
+#login-header-bar #add-user-button {
+  background-image: url('chrome://theme/IDR_ICON_ADD_USER_WHITE');
+}
+
+#login-header-bar #guest-user-button {
+  background-image: url('chrome://theme/IDR_ICON_GUEST_WHITE');
+}
+
+#login-header-bar button {
+  -webkit-padding-start: 24px;
+  background-position: left center;
+  background-repeat: no-repeat;
+  background-size: 24px;
+}
diff --git a/chrome/browser/resources/user_chooser/control_bar.html b/chrome/browser/resources/user_chooser/control_bar.html
new file mode 100644
index 0000000..2d44ee8
--- /dev/null
+++ b/chrome/browser/resources/user_chooser/control_bar.html
@@ -0,0 +1,9 @@
+<div id="login-header-bar" class="login-header-bar">
+  <div id="add-user-header-bar-item" class="header-bar-item">
+    <button id="add-user-button" i18n-content="addUser"></button>
+    <button id="cancel-add-user-button" i18n-content="cancel" hidden></button>
+  </div>
+  <div id="guest-user-header-bar-item" class="header-bar-item">
+    <button id="guest-user-button" i18n-content="browseAsGuest"></button>
+  </div>
+</div>
diff --git a/chrome/browser/resources/user_chooser/control_bar.js b/chrome/browser/resources/user_chooser/control_bar.js
new file mode 100644
index 0000000..2fe4ac4
--- /dev/null
+++ b/chrome/browser/resources/user_chooser/control_bar.js
@@ -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.
+
+/**
+ * @fileoverview Desktop User Chooser UI control bar implementation.
+ */
+
+cr.define('login', function() {
+  /**
+   * Creates a header bar element.
+   * @constructor
+   * @extends {HTMLDivElement}
+   */
+  var HeaderBar = cr.ui.define('div');
+
+  HeaderBar.prototype = {
+    __proto__: HTMLDivElement.prototype,
+
+    // Whether guest button should be shown when header bar is in normal mode.
+    showGuest_: true,
+
+    // Current UI state of the sign-in screen.
+    signinUIState_: SIGNIN_UI_STATE.ACCOUNT_PICKER,
+
+    // Whether to show kiosk apps menu.
+    hasApps_: false,
+
+    /** @override */
+    decorate: function() {
+      $('add-user-button').addEventListener('click',
+          this.handleAddUserClick_);
+      $('cancel-add-user-button').addEventListener('click',
+          this.handleCancelAddUserClick_);
+      $('guest-user-header-bar-item').addEventListener('click',
+          this.handleGuestClick_);
+      $('guest-user-button').addEventListener('click',
+          this.handleGuestClick_);
+      this.updateUI_();
+    },
+
+    /**
+     * Tab index value for all button elements.
+     * @type {number}
+     */
+    set buttonsTabIndex(tabIndex) {
+      var buttons = this.getElementsByTagName('button');
+      for (var i = 0, button; button = buttons[i]; ++i) {
+        button.tabIndex = tabIndex;
+      }
+    },
+
+    /**
+     * Disables the header bar and all of its elements.
+     * @type {boolean}
+     */
+    set disabled(value) {
+      var buttons = this.getElementsByTagName('button');
+      for (var i = 0, button; button = buttons[i]; ++i)
+        if (!button.classList.contains('button-restricted'))
+          button.disabled = value;
+    },
+
+    /**
+     * Add user button click handler.
+     * @private
+     */
+    handleAddUserClick_: function(e) {
+      chrome.send('addUser');
+      // Prevent further propagation of click event. Otherwise, the click event
+      // handler of document object will set wallpaper to user's wallpaper when
+      // there is only one existing user. See http://crbug.com/166477
+      e.stopPropagation();
+    },
+
+    /**
+     * Cancel add user button click handler.
+     * @private
+     */
+    handleCancelAddUserClick_: function(e) {
+      // Let screen handle cancel itself if that is capable of doing so.
+      if (Oobe.getInstance().currentScreen &&
+          Oobe.getInstance().currentScreen.cancel) {
+        Oobe.getInstance().currentScreen.cancel();
+        return;
+      }
+
+      Oobe.showScreen({id: SCREEN_ACCOUNT_PICKER});
+      Oobe.resetSigninUI(true);
+    },
+
+    /**
+     * Guest button click handler.
+     * @private
+     */
+    handleGuestClick_: function(e) {
+      chrome.send('launchGuest');
+      e.stopPropagation();
+    },
+
+    /**
+     * If true then "Browse as Guest" button is shown.
+     * @type {boolean}
+     */
+    set showGuestButton(value) {
+      this.showGuest_ = value;
+      this.updateUI_();
+    },
+
+    /**
+     * Update current header bar UI.
+     * @type {number} state Current state of the sign-in screen
+     *                      (see SIGNIN_UI_STATE).
+     */
+    set signinUIState(state) {
+      this.signinUIState_ = state;
+      this.updateUI_();
+    },
+
+    /**
+     * Whether the Cancel button is enabled during Gaia sign-in.
+     * @type {boolean}
+     */
+    set allowCancel(value) {
+      this.allowCancel_ = value;
+      this.updateUI_();
+    },
+
+    /**
+     * Updates visibility state of action buttons.
+     * @private
+     */
+    updateUI_: function() {
+      $('add-user-button').hidden = false;
+      $('cancel-add-user-button').hidden = !this.allowCancel_;
+      $('guest-user-header-bar-item').hidden = false;
+      $('add-user-header-bar-item').hidden = false;
+    },
+
+    /**
+     * Animates Header bar to hide from the screen.
+     * @param {function()} callback will be called once animation is finished.
+     */
+    animateOut: function(callback) {
+      var launcher = this;
+      launcher.addEventListener(
+          'webkitTransitionEnd', function f(e) {
+            launcher.removeEventListener('webkitTransitionEnd', f);
+            callback();
+          });
+      this.classList.remove('login-header-bar-animate-slow');
+      this.classList.add('login-header-bar-animate-fast');
+      this.classList.add('login-header-bar-hidden');
+    },
+
+    /**
+     * Animates Header bar to slowly appear on the screen.
+     */
+    animateIn: function() {
+      this.classList.remove('login-header-bar-animate-fast');
+      this.classList.add('login-header-bar-animate-slow');
+      this.classList.remove('login-header-bar-hidden');
+    },
+  };
+
+  /**
+   * Convenience wrapper of animateOut.
+   */
+  HeaderBar.animateOut = function(callback) {
+    $('login-header-bar').animateOut(callback);
+  };
+
+  /**
+   * Convenience wrapper of animateIn.
+   */
+  HeaderBar.animateIn = function() {
+    $('login-header-bar').animateIn();
+  }
+
+  return {
+    HeaderBar: HeaderBar
+  };
+});
diff --git a/chrome/browser/resources/user_chooser/desktop_user_pod_template.html b/chrome/browser/resources/user_chooser/desktop_user_pod_template.html
new file mode 100644
index 0000000..73a13cd
--- /dev/null
+++ b/chrome/browser/resources/user_chooser/desktop_user_pod_template.html
@@ -0,0 +1,25 @@
+<div id="user-pod-template" class="pod need-password" hidden>
+  <div class="main-pane">
+    <div class="signed-in-indicator" i18n-content="signedIn" hidden></div>
+    <img class="user-image" alt="">
+    <div class="name"></div>
+    <input type="password" class="password"
+           i18n-values="placeholder:passwordHint">
+    <button class="signin-button" i18n-content="signinButton"></button>
+  </div>
+  <div class="action-box-area">
+    <div class="custom-appearance action-box-button"></div>
+  </div>
+  <div class="user-type-icon-area" hidden>
+    <div class="custom-appearance user-type-icon-image"></div>
+  </div>
+  <div class="action-box-menu">
+    <div class="action-box-menu-title">
+      <span class="action-box-menu-title-name"></span>
+      <span class="action-box-menu-title-email"></span>
+    </div>
+    <div class="action-box-menu-remove">
+      <span class="action-box-menu-remove-command"/>
+    </div>
+  </div>
+</div>
diff --git a/chrome/browser/resources/user_chooser/user_chooser.html b/chrome/browser/resources/user_chooser/user_chooser.html
new file mode 100644
index 0000000..ccbea9d
--- /dev/null
+++ b/chrome/browser/resources/user_chooser/user_chooser.html
@@ -0,0 +1,50 @@
+<!DOCTYPE HTML>
+<html i18n-values="dir:textdirection;screen:screenType;build:buildType">
+<head>
+<title i18n-content="title"></title>
+<link rel="stylesheet" href="../chromeos/login/oobe.css">
+<link rel="stylesheet" href="../chromeos/login/user_pod_row.css">
+<!-- desktop user chooser specific overrides -->
+<link rel="stylesheet" href="control_bar.css">
+<link rel="stylesheet" href="../chromeos/login/bubble.css">
+<link rel="stylesheet" href="chrome://resources/css/chrome_shared.css">
+<link rel="stylesheet" href="../chromeos/login/screen_account_picker.css">
+<link rel="stylesheet" href="../chromeos/login/screen_container.css">
+<!-- framework imports -->
+<!-- as per chrome/browser/resources/chromeos/login/login_resources.html -->
+<script src="chrome://resources/js/cr.js"></script>
+<script src="chrome://resources/js/event_tracker.js"></script>
+<script src="chrome://resources/js/cr/event_target.js"></script>
+<script src="chrome://resources/js/cr/ui.js"></script>
+<script src="chrome://resources/js/cr/ui/array_data_model.js"></script>
+<script src="chrome://resources/js/cr/ui/list_selection_controller.js"></script>
+<script src="chrome://resources/js/cr/ui/list_selection_model.js"></script>
+<script src="chrome://resources/js/cr/ui/list_single_selection_model.js"></script>
+<script src="chrome://resources/js/cr/ui/list.js"></script>
+<script src="chrome://resources/js/cr/ui/list_item.js"></script>
+<script src="chrome://resources/js/cr/ui/grid.js"></script>
+<script src="chrome://resources/js/cr/ui/menu_item.js"></script>
+<script src="chrome://resources/js/cr/ui/menu.js"></script>
+<script src="chrome://resources/js/cr/ui/menu_button.js"></script>
+<script src="chrome://resources/js/load_time_data.js"></script>
+<script src="chrome://resources/js/util.js"></script>
+<script src="user_chooser.js"></script>
+<script src="chrome://user-chooser/strings.js"></script>
+</head>
+<body class="login-display" i18n-values=".style.fontFamily:fontfamily;">
+  <div id="outer-container">
+    <div id="oobe" class="faded">
+      <div id="inner-container">
+        <div id="step-logo" hidden>
+          <div id="header-sections"></div>
+        </div>
+        <include src="../chromeos/login/screen_account_picker.html">
+      </div>
+    </div>
+  </div>
+  <div id="bubble" class="bubble faded" hidden></div>
+  <include src="control_bar.html">
+  <include src="desktop_user_pod_template.html">
+  <script src="chrome://resources/js/i18n_template2.js"></script>
+</body>
+</html>
diff --git a/chrome/browser/resources/user_chooser/user_chooser.js b/chrome/browser/resources/user_chooser/user_chooser.js
new file mode 100644
index 0000000..a98e703
--- /dev/null
+++ b/chrome/browser/resources/user_chooser/user_chooser.js
@@ -0,0 +1,119 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+<include src="../chromeos/login/screen.js"></include>
+<include src="../chromeos/login/bubble.js"></include>
+<include src="../chromeos/login/display_manager.js"></include>
+<include src="control_bar.js"></include>
+<include src="../chromeos/login/screen_account_picker.js"></include>
+<include src="../chromeos/login/user_pod_row.js"></include>
+<include src="../chromeos/login/resource_loader.js"></include>
+
+cr.define('cr.ui', function() {
+  var DisplayManager = cr.ui.login.DisplayManager;
+
+  /**
+  * Constructs an Out of box controller. It manages initialization of screens,
+  * transitions, error messages display.
+  * @extends {DisplayManager}
+  * @constructor
+  */
+  function Oobe() {
+  }
+
+  cr.addSingletonGetter(Oobe);
+
+  Oobe.prototype = {
+    __proto__: DisplayManager.prototype,
+  };
+
+  /**
+   * Shows the given screen.
+   * @param {Object} screen Screen params dict, e.g. {id: screenId, data: data}
+   */
+  Oobe.showUserChooserScreen = function() {
+    Oobe.getInstance().showScreen({id: 'account-picker',
+                                   data: {disableAddUser: false}});
+    // The ChromeOS account-picker will hide the AddUser button if a user is
+    // logged in and the screen is "locked", so we must re-enabled it
+    $('add-user-header-bar-item').hidden = false;
+  };
+
+  /**
+   * Shows signin UI.
+   * @param {string} opt_email An optional email for signin UI.
+   */
+  Oobe.launchUser = function(email, displayName) {
+    chrome.send('launchUser', [email, displayName]);
+  };
+
+  /**
+   * Disables signin UI.
+   */
+  Oobe.disableSigninUI = function() {
+    DisplayManager.disableSigninUI();
+  };
+
+  /**
+   * Shows signin UI.
+   * @param {string} opt_email An optional email for signin UI.
+   */
+  Oobe.showSigninUI = function(opt_email) {
+    DisplayManager.showSigninUI(opt_email);
+  };
+
+  /**
+   * Clears error bubble as well as optional menus that could be open.
+   */
+  Oobe.clearErrors = function() {
+    DisplayManager.clearErrors();
+  };
+
+  /**
+   * Clears password field in user-pod.
+   */
+  Oobe.clearUserPodPassword = function() {
+    DisplayManager.clearUserPodPassword();
+  };
+
+  /**
+   * Restores input focus to currently selected pod.
+   */
+  Oobe.refocusCurrentPod = function() {
+    DisplayManager.refocusCurrentPod();
+  };
+
+  // Export
+  return {
+    Oobe: Oobe
+  };
+});
+
+cr.define('UserChooser', function() {
+  'use strict';
+
+  function initialize() {
+    login.AccountPickerScreen.register();
+    cr.ui.Bubble.decorate($('bubble'));
+    login.HeaderBar.decorate($('login-header-bar'));
+    chrome.send('userChooserInitialize');
+  }
+
+  // Return an object with all of the exports.
+  return {
+    initialize: initialize
+  };
+});
+
+var Oobe = cr.ui.Oobe;
+
+// Allow selection events on components with editable text (password field)
+// bug (http://code.google.com/p/chromium/issues/detail?id=125863)
+disableTextSelectAndDrag(function(e) {
+  var src = e.target;
+  return src instanceof HTMLTextAreaElement ||
+         src instanceof HTMLInputElement &&
+         /text|password|search/.test(src.type);
+});
+
+document.addEventListener('DOMContentLoaded', UserChooser.initialize);
diff --git a/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc b/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc
index 70683c5..485046f 100644
--- a/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc
@@ -35,6 +35,10 @@
 #include "content/public/test/test_browser_thread.h"
 #include "content/public/test/test_utils.h"
 
+#if defined(OS_WIN) && defined(USE_ASH)
+#include "base/win/windows_version.h"
+#endif
+
 using content::BrowserThread;
 using content::InterstitialPage;
 using content::NavigationController;
@@ -616,6 +620,12 @@
 }
 
 IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageTest, MalwareDontProceed) {
+#if defined(OS_WIN) && defined(USE_ASH)
+  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
+  if (base::win::GetVersion() >= base::win::VERSION_WIN8)
+    return;
+#endif
+
   SetupWarningAndNavigate(SB_THREAT_TYPE_URL_MALWARE);
 
   EXPECT_EQ(VISIBLE, GetVisibility("malware-icon"));
@@ -661,6 +671,12 @@
 
 IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageTest,
                        MalwareIframeDontProceed) {
+#if defined(OS_WIN) && defined(USE_ASH)
+  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
+  if (base::win::GetVersion() >= base::win::VERSION_WIN8)
+    return;
+#endif
+
   SetupMalwareIframeWarningAndNavigate();
 
   EXPECT_EQ(HIDDEN, GetVisibility("malware-icon"));
@@ -717,6 +733,12 @@
 // by the corresponding policy. Also verifies that sending the "proceed"
 // command anyway doesn't advance to the malware site.
 IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageTest, ProceedDisabled) {
+#if defined(OS_WIN) && defined(USE_ASH)
+  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
+  if (base::win::GetVersion() >= base::win::VERSION_WIN8)
+    return;
+#endif
+
   // Simulate a policy disabling the "proceed anyway" link.
   browser()->profile()->GetPrefs()->SetBoolean(
       prefs::kSafeBrowsingProceedAnywayDisabled, true);
@@ -744,6 +766,12 @@
 // TODO(mattm): Should also verify that no report is sent, but there isn't a
 // good way to do that in the current design.
 IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageTest, ReportingDisabled) {
+#if defined(OS_WIN) && defined(USE_ASH)
+  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
+  if (base::win::GetVersion() >= base::win::VERSION_WIN8)
+    return;
+#endif
+
   browser()->profile()->GetPrefs()->SetBoolean(
       prefs::kSafeBrowsingReportingEnabled, true);
 
@@ -771,6 +799,12 @@
 }
 
 IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageTest, PhishingDontProceed) {
+#if defined(OS_WIN) && defined(USE_ASH)
+  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
+  if (base::win::GetVersion() >= base::win::VERSION_WIN8)
+    return;
+#endif
+
   SetupWarningAndNavigate(SB_THREAT_TYPE_URL_PHISHING);
 
   EXPECT_EQ(HIDDEN, GetVisibility("malware-icon"));
diff --git a/chrome/browser/search/instant_service.cc b/chrome/browser/search/instant_service.cc
index 20fb466..014cbf8 100644
--- a/chrome/browser/search/instant_service.cc
+++ b/chrome/browser/search/instant_service.cc
@@ -56,6 +56,8 @@
 
 InstantService::InstantService(Profile* profile)
     : profile_(profile),
+      ntp_prerenderer_(profile, profile->GetPrefs()),
+      browser_instant_controller_object_count_(0),
       weak_ptr_factory_(this) {
   // Stub for unit tests.
   if (!BrowserThread::CurrentlyOn(BrowserThread::UI))
@@ -174,6 +176,37 @@
   instant_io_context_ = NULL;
 }
 
+scoped_ptr<content::WebContents> InstantService::ReleaseNTPContents() {
+  return ntp_prerenderer_.ReleaseNTPContents();
+}
+
+content::WebContents* InstantService::GetNTPContents() const {
+  return ntp_prerenderer_.GetNTPContents();
+}
+
+void InstantService::OnBrowserInstantControllerCreated() {
+  if (profile_->IsOffTheRecord())
+    return;
+
+  ++browser_instant_controller_object_count_;
+
+  if (browser_instant_controller_object_count_ == 1)
+    ntp_prerenderer_.PreloadInstantNTP();
+}
+
+void InstantService::OnBrowserInstantControllerDestroyed() {
+  if (profile_->IsOffTheRecord())
+    return;
+
+  DCHECK_GT(browser_instant_controller_object_count_, 0U);
+  --browser_instant_controller_object_count_;
+
+  // All browser windows have closed, so release the InstantNTP resources to
+  // work around http://crbug.com/180810.
+  if (browser_instant_controller_object_count_ == 0)
+    ntp_prerenderer_.DeleteNTPContents();
+}
+
 void InstantService::Observe(int type,
                              const content::NotificationSource& source,
                              const content::NotificationDetails& details) {
@@ -348,3 +381,7 @@
   FOR_EACH_OBSERVER(InstantServiceObserver, observers_,
                     ThemeInfoChanged(*theme_info_));
 }
+
+InstantNTPPrerenderer* InstantService::ntp_prerenderer() {
+  return &ntp_prerenderer_;
+}
diff --git a/chrome/browser/search/instant_service.h b/chrome/browser/search/instant_service.h
index 1e0d6f3..789d5c7 100644
--- a/chrome/browser/search/instant_service.h
+++ b/chrome/browser/search/instant_service.h
@@ -12,22 +12,30 @@
 
 #include "base/basictypes.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/weak_ptr.h"
 #include "base/observer_list.h"
 #include "chrome/browser/history/history_types.h"
+#include "chrome/browser/ui/search/instant_ntp_prerenderer.h"
 #include "chrome/common/instant_types.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 GURL;
+class InstantExtendedTest;
 class InstantIOContext;
 class InstantServiceObserver;
+class InstantTestBase;
 class Profile;
 class ThemeService;
 
+namespace content {
+class WebContents;
+}
+
 namespace net {
 class URLRequest;
 }
@@ -78,7 +86,33 @@
   // NTP.
   void UpdateMostVisitedItemsInfo();
 
+  // Forwards the request to InstantNTPPrerenderer to release and return the
+  // preloaded InstantNTP WebContents. May be NULL. InstantNTPPrerenderer will
+  // load a new InstantNTP after releasing the preloaded contents.
+  scoped_ptr<content::WebContents> ReleaseNTPContents() WARN_UNUSED_RESULT;
+
+  // The NTP WebContents. May be NULL. InstantNTPPrerenderer retains ownership.
+  content::WebContents* GetNTPContents() const;
+
+  // Notifies InstantService about the creation of a BrowserInstantController
+  // object. Used to preload InstantNTP.
+  void OnBrowserInstantControllerCreated();
+
+  // Notifies InstantService about the destruction of a BrowserInstantController
+  // object. Used to destroy the preloaded InstantNTP.
+  void OnBrowserInstantControllerDestroyed();
+
  private:
+  friend class InstantExtendedTest;
+  friend class InstantTestBase;
+
+  FRIEND_TEST_ALL_PREFIXES(InstantExtendedNetworkTest,
+                           NTPReactsToNetworkChanges);
+  FRIEND_TEST_ALL_PREFIXES(InstantExtendedManualTest,
+                           MANUAL_ShowsGoogleNTP);
+  FRIEND_TEST_ALL_PREFIXES(InstantExtendedManualTest,
+                           MANUAL_SearchesFromFakebox);
+
   // Overridden from BrowserContextKeyedService:
   virtual void Shutdown() OVERRIDE;
 
@@ -98,6 +132,9 @@
   // Theme changed notification handler.
   void OnThemeChanged(ThemeService* theme_service);
 
+  // Used by tests.
+  InstantNTPPrerenderer* ntp_prerenderer();
+
   Profile* const profile_;
 
   // The process ids associated with Instant processes.
@@ -115,6 +152,12 @@
 
   scoped_refptr<InstantIOContext> instant_io_context_;
 
+  InstantNTPPrerenderer ntp_prerenderer_;
+
+  // Total number of BrowserInstantController objects (does not include objects
+  // created for OTR browser windows). Used to preload and delete InstantNTP.
+  size_t browser_instant_controller_object_count_;
+
   // Used for Top Sites async retrieval.
   base::WeakPtrFactory<InstantService> weak_ptr_factory_;
 
diff --git a/chrome/browser/search/local_ntp_source.cc b/chrome/browser/search/local_ntp_source.cc
index e95bd57..66fef8a 100644
--- a/chrome/browser/search/local_ntp_source.cc
+++ b/chrome/browser/search/local_ntp_source.cc
@@ -46,14 +46,6 @@
   { "images/close_2_hover.png", IDR_CLOSE_2_H, "image/png" },
   { "images/close_2_active.png", IDR_CLOSE_2_P, "image/png" },
   { "images/close_2_white.png", IDR_CLOSE_2_MASK, "image/png" },
-  { "images/page_icon.png", IDR_LOCAL_OMNIBOX_POPUP_IMAGES_PAGE_ICON_PNG,
-    "image/png" },
-  { "images/2x/page_icon.png",
-    IDR_LOCAL_OMNIBOX_POPUP_IMAGES_2X_PAGE_ICON_PNG, "image/png" },
-  { "images/search_icon.png",
-    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/2x/google_logo.png",
     IDR_LOCAL_NTP_IMAGES_2X_LOGO_PNG, "image/png" },
   { "images/2x/white_google_logo.png",
diff --git a/chrome/browser/search/search.cc b/chrome/browser/search/search.cc
index b38c8b7..ec6b193 100644
--- a/chrome/browser/search/search.cc
+++ b/chrome/browser/search/search.cc
@@ -11,8 +11,10 @@
 #include "base/rand_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
+#include "chrome/browser/browser_process.h"
 #include "chrome/browser/google/google_util.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/search/instant_service.h"
 #include "chrome/browser/search/instant_service_factory.h"
 #include "chrome/browser/search_engines/template_url_service.h"
@@ -371,10 +373,6 @@
   return false;
 }
 
-bool ShouldPreloadInstantNTP(Profile* profile) {
-  return !GetInstantURL(profile, kDisableStartMargin).is_empty();
-}
-
 bool ShouldShowInstantNTP() {
   FieldTrialFlags flags;
   if (GetFieldTrialInfo(
@@ -415,6 +413,20 @@
   std::string search_scheme(chrome::kChromeSearchScheme);
   replacements.SetScheme(search_scheme.data(),
                          url_parse::Component(0, search_scheme.length()));
+
+  // If the URL corresponds to an online NTP, replace the host with
+  // "online-ntp".
+  std::string online_ntp_host(chrome::kChromeSearchOnlineNtpHost);
+  TemplateURL* template_url = GetDefaultSearchProviderTemplateURL(profile);
+  if (template_url) {
+    const GURL instant_url = TemplateURLRefToGURL(
+        template_url->instant_url_ref(), kDisableStartMargin, false);
+    if (instant_url.is_valid() && MatchesOriginAndPath(url, instant_url)) {
+      replacements.SetHost(online_ntp_host.c_str(),
+                           url_parse::Component(0, online_ntp_host.length()));
+    }
+  }
+
   privileged_url = privileged_url.ReplaceComponents(replacements);
   return privileged_url;
 }
@@ -446,11 +458,16 @@
 }
 
 bool IsPreloadedInstantExtendedNTP(const content::WebContents* contents) {
-  for (chrome::BrowserIterator it; !it.done(); it.Next()) {
-    if (it->instant_controller() &&
-        it->instant_controller()->instant()->GetNTPContents() == contents) {
+  ProfileManager* profile_manager = g_browser_process->profile_manager();
+  if (!profile_manager)
+    return false;  // The profile manager can be NULL while testing.
+
+  const std::vector<Profile*>& profiles = profile_manager->GetLoadedProfiles();
+  for (size_t i = 0; i < profiles.size(); ++i) {
+    const InstantService* instant_service =
+        InstantServiceFactory::GetForProfile(profiles[i]);
+    if (instant_service && instant_service->GetNTPContents() == contents)
       return true;
-    }
   }
   return false;
 }
diff --git a/chrome/browser/search/search.h b/chrome/browser/search/search.h
index c4338ec..f7630a5 100644
--- a/chrome/browser/search/search.h
+++ b/chrome/browser/search/search.h
@@ -105,9 +105,6 @@
 // to always show the remote NTP on browser startup.
 bool ShouldPreferRemoteNTPOnStartup();
 
-// Returns true if the Instant NTP should be preloaded before it is shown.
-bool ShouldPreloadInstantNTP(Profile* profile);
-
 // Returns true if the Instant NTP should be shown and false if not.
 bool ShouldShowInstantNTP();
 
@@ -131,6 +128,10 @@
 // Notice the scheme change.
 //
 // If the input is already a privileged URL then that same URL is returned.
+//
+// If |url| is that of the online NTP, its host is replaced with "online-ntp".
+// This forces the NTP and search results pages to have different SiteIntances,
+// and hence different processes.
 GURL GetPrivilegedURLForInstant(const GURL& url, Profile* profile);
 
 // Returns true if the input |url| is a privileged Instant URL.
diff --git a/chrome/browser/search/search_unittest.cc b/chrome/browser/search/search_unittest.cc
index 0172f2a..b718e06 100644
--- a/chrome/browser/search/search_unittest.cc
+++ b/chrome/browser/search/search_unittest.cc
@@ -19,6 +19,9 @@
 #include "chrome/common/url_constants.h"
 #include "chrome/test/base/browser_with_test_window_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/site_instance.h"
 #include "content/public/browser/web_contents.h"
 
 namespace chrome {
@@ -287,6 +290,112 @@
   }
 }
 
+struct PrivilegedURLTestCase {
+  bool add_as_alternate_url;
+  const char* input_url;
+  const char* privileged_url;
+  bool different_site_instance;
+  const char* comment;
+};
+
+TEST_F(SearchTest, GetPrivilegedURLForInstant) {
+  EnableInstantExtendedAPIForTesting();
+
+  const PrivilegedURLTestCase kTestCases[] = {
+    { false,  // don't append input_url as alternate URL.
+      chrome::kChromeSearchLocalNtpUrl,  // input URL.
+      chrome::kChromeSearchLocalNtpUrl,  // expected privileged URL.
+      true,  // expected different SiteInstance.
+      "local NTP" },
+    { false,  // don't append input_url as alternate URL.
+      "https://foo.com/instant?strk",
+      "chrome-search://online-ntp/instant?strk",
+      true,  // expected different SiteInstance.
+      "Valid Instant NTP" },
+    { false,  // don't append input_url as alternate URL.
+      "https://foo.com/instant?strk&more=junk",
+      "chrome-search://online-ntp/instant?strk&more=junk",
+      true,  // expected different SiteInstance.
+      "Valid Instant NTP with extra query" },
+    { false,  // don't append input_url as alternate URL.
+      "https://foo.com/url?strk",
+      "chrome-search://foo.com/url?strk",
+      false,  // expected same SiteInstance.
+      "Search URL" },
+    { true,  // append input_url as alternate URL.
+      "https://notfoo.com/instant?strk",
+      "chrome-search://notfoo.com/instant?strk",
+      true,  // expected different SiteInstance.
+      "Invalid host in URL" },
+    { true,  // append input_url as alternate URL.
+      "https://foo.com/webhp?strk",
+      "chrome-search://foo.com/webhp?strk",
+      false,  // expected same SiteInstance.
+      "Invalid path in URL" },
+    { true,  // append input_url as alternate URL.
+      "https://foo.com/search?strk",
+      "chrome-search://foo.com/search?strk",
+      false,  // expected same SiteInstance.
+      "Invalid path in URL" },
+  };
+
+  // GetPrivilegedURLForInstant expects ShouldAssignURLToInstantRenderer to
+  // be true, and the latter expects chrome-search: scheme or IsInstantURL to be
+  // true.  To force IsInstantURL to return true, add the input_url of each
+  // PrivilegedURLTestCase as the alternate URL for the default template URL.
+  const char* kSearchURL = "https://foo.com/url?strk";
+  TemplateURLService* template_url_service =
+      TemplateURLServiceFactory::GetForProfile(profile());
+  TemplateURLData data;
+  data.SetURL(kSearchURL);
+  data.instant_url = "http://foo.com/instant?strk";
+  data.search_terms_replacement_key = "strk";
+  for (size_t i = 0; i < arraysize(kTestCases); ++i) {
+    const PrivilegedURLTestCase& test = kTestCases[i];
+    if (test.add_as_alternate_url)
+      data.alternate_urls.push_back(test.input_url);
+  }
+  TemplateURL* template_url = new TemplateURL(profile(), data);
+  // Takes ownership of |template_url|.
+  template_url_service->Add(template_url);
+  template_url_service->SetDefaultSearchProvider(template_url);
+
+  AddTab(browser(), GURL("chrome://blank"));
+  for (size_t i = 0; i < arraysize(kTestCases); ++i) {
+    const PrivilegedURLTestCase& test = kTestCases[i];
+
+    // Verify GetPrivilegedURLForInstant.
+    EXPECT_EQ(GURL(test.privileged_url),
+              GetPrivilegedURLForInstant(GURL(test.input_url), profile()))
+        << test.input_url << " " << test.comment;
+
+    // Verify that navigating from input_url to search URL results in same or
+    // different SiteInstance.
+    // First, navigate to input_url.
+    NavigateAndCommitActiveTab(GURL(test.input_url));
+    content::WebContents* contents =
+        browser()->tab_strip_model()->GetWebContentsAt(0);
+    // Cache the SiteInstance, RenderViewHost and RenderProcessHost for
+    // input_url.
+    const scoped_refptr<content::SiteInstance> prev_site_instance =
+        contents->GetSiteInstance();
+    const content::RenderViewHost* prev_rvh = contents->GetRenderViewHost();
+    const content::RenderProcessHost* prev_rph =
+        contents->GetRenderProcessHost();
+    // Then, navigate to search URL.
+    NavigateAndCommitActiveTab(GURL(kSearchURL));
+    EXPECT_EQ(test.different_site_instance,
+              contents->GetSiteInstance() != prev_site_instance)
+        << test.input_url << " " << test.comment;
+    EXPECT_EQ(test.different_site_instance,
+              contents->GetRenderViewHost() != prev_rvh)
+        << test.input_url << " " << test.comment;
+    EXPECT_EQ(test.different_site_instance,
+              contents->GetRenderProcessHost() != prev_rph)
+        << test.input_url << " " << test.comment;
+  }
+}
+
 const SearchTestCase kInstantNTPTestCases[] = {
   {"https://foo.com/instant?strk",         true,  "Valid Instant URL"},
   {"https://foo.com/instant#strk",         true,  "Valid Instant URL"},
diff --git a/chrome/browser/search_engines/template_url_service.cc b/chrome/browser/search_engines/template_url_service.cc
index e897739..7392921 100644
--- a/chrome/browser/search_engines/template_url_service.cc
+++ b/chrome/browser/search_engines/template_url_service.cc
@@ -20,6 +20,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
 #include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/google/google_url_tracker.h"
 #include "chrome/browser/history/history_notifications.h"
 #include "chrome/browser/history/history_service.h"
@@ -36,6 +37,7 @@
 #include "chrome/browser/webdata/web_data_service.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/env_vars.h"
+#include "chrome/common/extensions/api/omnibox/omnibox_handler.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/url_constants.h"
 #include "content/public/browser/notification_service.h"
@@ -244,8 +246,52 @@
   UMA_HISTOGRAM_COUNTS_100("Search.SearchEngineDuplicateCounts", num_dupes);
 }
 
+typedef std::vector<TemplateURLService::ExtensionKeyword> ExtensionKeywords;
+
+#if !defined(OS_ANDROID)
+// Extract all installed Omnibox Extensions.
+ExtensionKeywords GetExtensionKeywords(Profile* profile) {
+  DCHECK(profile);
+  ExtensionService* extension_service = profile->GetExtensionService();
+  DCHECK(extension_service);
+  const ExtensionSet* extensions = extension_service->extensions();
+  ExtensionKeywords extension_keywords;
+  for (ExtensionSet::const_iterator it = extensions->begin();
+       it != extensions->end(); ++it) {
+    const std::string& keyword = extensions::OmniboxInfo::GetKeyword(*it);
+    if (!keyword.empty()) {
+      extension_keywords.push_back(TemplateURLService::ExtensionKeyword(
+          (*it)->id(), (*it)->name(), keyword));
+    }
+  }
+  return extension_keywords;
+}
+#else
+// Extensions are not supported.
+ExtensionKeywords GetExtensionKeywords(Profile* profile) {
+  return ExtensionKeywords();
+}
+#endif
+
 }  // namespace
 
+
+// TemplateURLService::ExtensionKeyword ---------------------------------------
+
+TemplateURLService::ExtensionKeyword::ExtensionKeyword(
+    const std::string& id,
+    const std::string& name,
+    const std::string& keyword)
+    : extension_id(id),
+      extension_name(name),
+      extension_keyword(keyword) {
+}
+
+TemplateURLService::ExtensionKeyword::~ExtensionKeyword() {}
+
+
+// TemplateURLService::LessWithPrefix -----------------------------------------
+
 class TemplateURLService::LessWithPrefix {
  public:
   // We want to find the set of keywords that begin with a prefix.  The STL
@@ -268,6 +314,9 @@
   }
 };
 
+
+// TemplateURLService ---------------------------------------------------------
+
 TemplateURLService::TemplateURLService(Profile* profile)
     : provider_map_(new SearchHostToURLsMap),
       profile_(profile),
@@ -545,14 +594,8 @@
   DCHECK(loaded_);
 
   if (!GetTemplateURLForExtension(extension_id)) {
-    TemplateURLData data;
-    data.short_name = UTF8ToUTF16(extension_name);
-    data.SetKeyword(UTF8ToUTF16(keyword));
-    // This URL is not actually used for navigation. It holds the extension's
-    // ID, as well as forcing the TemplateURL to be treated as a search keyword.
-    data.SetURL(std::string(extensions::kExtensionScheme) + "://" +
-        extension_id + "/?q={searchTerms}");
-    Add(new TemplateURL(profile_, data));
+    ExtensionKeyword extension_url(extension_id, extension_name, keyword);
+    Add(CreateTemplateURLForExtension(extension_url));
   }
 }
 
@@ -670,30 +713,20 @@
   return FirstPotentialDefaultEngine(template_urls_);
 }
 
-void TemplateURLService::ResetNonExtensionURLs() {
+void TemplateURLService::ResetURLs() {
   // Can't clean DB if it hasn't been loaded.
   DCHECK(loaded());
+  DCHECK(service_);
   ClearDefaultProviderFromPrefs();
 
-  // Preserve all extension URLs, as they should not be reset.
-  TemplateURLVector entries_to_process;
-  for (TemplateURLVector::const_iterator i = template_urls_.begin();
-       i != template_urls_.end(); ++i) {
-    if (!(*i)->IsExtensionKeyword())
-      entries_to_process.push_back(*i);
-  }
+  TemplateURLVector entries_to_process = template_urls_;
   // Clear default provider to be able to delete it.
   default_search_provider_ = NULL;
   for (TemplateURLVector::const_iterator i = entries_to_process.begin();
        i != entries_to_process.end(); ++i)
     RemoveNoNotify(*i);
 
-  // Store the remaining engines in entries_to_process and merge them with
-  // prepopulated ones. NOTE: Because this class owns the pointers stored in
-  // |template_urls_|, the swap() call below means this function is taking
-  // ownership of all these pointers; see comments below.
   entries_to_process.clear();
-  entries_to_process.swap(template_urls_);
   provider_map_.reset(new SearchHostToURLsMap);
   UIThreadSearchTermsData search_terms_data(profile_);
   provider_map_->Init(TemplateURLVector(), search_terms_data);
@@ -708,24 +741,21 @@
                                        &default_search_provider,
                                        &new_resource_keyword_version,
                                        &pre_sync_deletes_);
-  // We don't want to pass any extension URLs to
-  // AddTemplateURLsAndSetupDefaultEngine(), since they were never removed
-  // from the model to begin with.
-  TemplateURLVector::iterator extensions(std::partition(
-      entries_to_process.begin(), entries_to_process.end(),
-      std::not1(std::mem_fun(&TemplateURL::IsExtensionKeyword))));
-  // Right now we own all pointers in |entries_to_process| (see above).
-  // AddTemplateURLsAndSetupDefaultEngine() will take ownership of all
-  // passed-in TemplateURLs (generally by passing them to AddNoNotify()). Any
-  // URLs we aren't going to pass to it have to be freed here.
-  STLDeleteContainerPointers(extensions, entries_to_process.end());
-  entries_to_process.erase(extensions, entries_to_process.end());
   // Setup search engines and a default one.
   base::AutoReset<DefaultSearchChangeOrigin> change_origin(
       &dsp_change_origin_, DSP_CHANGE_PROFILE_RESET);
   AddTemplateURLsAndSetupDefaultEngine(&entries_to_process,
                                        default_search_provider);
 
+  // Repopulate extension keywords.
+  std::vector<ExtensionKeyword> extension_keywords =
+      GetExtensionKeywords(profile());
+  for (size_t i = 0; i < extension_keywords.size(); ++i) {
+    TemplateURL* extension_url =
+        CreateTemplateURLForExtension(extension_keywords[i]);
+    AddNoNotify(extension_url, true);
+  }
+
   if (new_resource_keyword_version)
     service_->SetBuiltinKeywordVersion(new_resource_keyword_version);
 
@@ -2544,3 +2574,15 @@
     }
   }
 }
+
+TemplateURL* TemplateURLService::CreateTemplateURLForExtension(
+    const ExtensionKeyword& extension_keyword) const {
+  TemplateURLData data;
+  data.short_name = UTF8ToUTF16(extension_keyword.extension_name);
+  data.SetKeyword(UTF8ToUTF16(extension_keyword.extension_keyword));
+  // This URL is not actually used for navigation. It holds the extension's
+  // ID, as well as forcing the TemplateURL to be treated as a search keyword.
+  data.SetURL(std::string(extensions::kExtensionScheme) + "://" +
+      extension_keyword.extension_id + "/?q={searchTerms}");
+  return new TemplateURL(profile_, data);
+}
diff --git a/chrome/browser/search_engines/template_url_service.h b/chrome/browser/search_engines/template_url_service.h
index 31d6186..a7e3e24 100644
--- a/chrome/browser/search_engines/template_url_service.h
+++ b/chrome/browser/search_engines/template_url_service.h
@@ -79,6 +79,18 @@
     const char* const content;
   };
 
+  // Struct describes a search engine added by an extension.
+  struct ExtensionKeyword {
+    ExtensionKeyword(const std::string& id,
+                     const std::string& name,
+                     const std::string& keyword);
+    ~ExtensionKeyword();
+
+    std::string extension_id;
+    std::string extension_name;
+    std::string extension_keyword;
+  };
+
   explicit TemplateURLService(Profile* profile);
   // The following is for testing.
   TemplateURLService(const Initializer* initializers, const int count);
@@ -225,10 +237,12 @@
   // destroyed at any time so should be used right after the call.
   TemplateURL* FindNewDefaultSearchProvider();
 
-  // Resets the search providers to the prepopulated engines plus any
-  // extension-supplied engines.  Also resets the default search engine unless
-  // it's managed.
-  void ResetNonExtensionURLs();
+  // Resets the search providers to the prepopulated engines plus any keywords
+  // from currently-installed extensions.  The user will lose all auto-added
+  // keywords from webpages, all edits to both normal and extension keywords,
+  // and any keywords belonging to no-longer-installed extensions.
+  // Modifications will be synced later.
+  void ResetURLs();
 
   // Observers used to listen for changes to the model.
   // TemplateURLService does NOT delete the observers when deleted.
@@ -362,7 +376,7 @@
                            IsLocalTemplateURLBetter);
   FRIEND_TEST_ALL_PREFIXES(TemplateURLServiceSyncTest, MergeInSyncTemplateURL);
 
-  friend class TemplateURLServiceTestUtil;
+  friend class TemplateURLServiceTestUtilBase;
 
   typedef std::map<string16, TemplateURL*> KeywordToTemplateMap;
   typedef std::map<std::string, TemplateURL*> GUIDToTemplateMap;
@@ -605,6 +619,10 @@
   // result of calling FindNewDefaultSearchProvider().
   void EnsureDefaultSearchProviderExists();
 
+  // Returns a new TemplateURL for the given extension.
+  TemplateURL* CreateTemplateURLForExtension(
+      const ExtensionKeyword& extension_keyword) const;
+
   content::NotificationRegistrar notification_registrar_;
   PrefChangeRegistrar pref_change_registrar_;
 
diff --git a/chrome/browser/search_engines/template_url_service_android.cc b/chrome/browser/search_engines/template_url_service_android.cc
index e03325d..262dc34 100644
--- a/chrome/browser/search_engines/template_url_service_android.cc
+++ b/chrome/browser/search_engines/template_url_service_android.cc
@@ -100,6 +100,14 @@
   return template_url_service_->is_default_search_managed();
 }
 
+jboolean TemplateUrlServiceAndroid::IsDefaultSearchEngineGoogle(JNIEnv* env,
+                                                                jobject obj) {
+  TemplateURL* default_search_provider =
+      template_url_service_->GetDefaultSearchProvider();
+  return default_search_provider &&
+      default_search_provider->url_ref().HasGoogleBaseURLs();
+}
+
 base::android::ScopedJavaLocalRef<jobject>
 TemplateUrlServiceAndroid::GetPrepopulatedTemplateUrlAt(JNIEnv* env,
                                                         jobject obj,
diff --git a/chrome/browser/search_engines/template_url_service_android.h b/chrome/browser/search_engines/template_url_service_android.h
index 97336e8..9c6fad5 100644
--- a/chrome/browser/search_engines/template_url_service_android.h
+++ b/chrome/browser/search_engines/template_url_service_android.h
@@ -29,6 +29,7 @@
   base::android::ScopedJavaLocalRef<jobject>
       GetPrepopulatedTemplateUrlAt(JNIEnv* env, jobject obj, jint index);
   jboolean IsSearchProviderManaged(JNIEnv* env, jobject obj);
+  jboolean IsDefaultSearchEngineGoogle(JNIEnv* env, jobject obj);
 
   // NotificationObserver:
   virtual void Observe(int type,
diff --git a/chrome/browser/search_engines/template_url_service_test_util.cc b/chrome/browser/search_engines/template_url_service_test_util.cc
index 18e2964..850b5e3 100644
--- a/chrome/browser/search_engines/template_url_service_test_util.cc
+++ b/chrome/browser/search_engines/template_url_service_test_util.cc
@@ -54,6 +54,9 @@
 
 }  // namespace
 
+
+// TestingTemplateURLService --------------------------------------------------
+
 // Trivial subclass of TemplateURLService that records the last invocation of
 // SetKeywordSearchTermsForURL.
 class TestingTemplateURLService : public TemplateURLService {
@@ -85,90 +88,45 @@
   DISALLOW_COPY_AND_ASSIGN(TestingTemplateURLService);
 };
 
-TemplateURLServiceTestUtil::TemplateURLServiceTestUtil()
-    : ui_thread_(BrowserThread::UI, &message_loop_),
-      db_thread_(BrowserThread::DB),
-      io_thread_(BrowserThread::IO),
-      changed_count_(0) {
+
+// TemplateURLServiceTestUtilBase ---------------------------------------------
+
+TemplateURLServiceTestUtilBase::TemplateURLServiceTestUtilBase()
+    : changed_count_(0) {
 }
 
-TemplateURLServiceTestUtil::~TemplateURLServiceTestUtil() {
-}
+TemplateURLServiceTestUtilBase::~TemplateURLServiceTestUtilBase() {}
 
-void TemplateURLServiceTestUtil::SetUp() {
-  // Make unique temp directory.
-  ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
-  profile_.reset(new TestingProfile(temp_dir_.path()));
-  db_thread_.Start();
-  profile_->CreateWebDataService();
+void TemplateURLServiceTestUtilBase::CreateTemplateUrlService() {
+  profile()->CreateWebDataService();
 
   TemplateURLService* service = static_cast<TemplateURLService*>(
       TemplateURLServiceFactory::GetInstance()->SetTestingFactoryAndUse(
-          profile_.get(), TestingTemplateURLService::Build));
+          profile(), TestingTemplateURLService::Build));
   service->AddObserver(this);
-
-#if defined(OS_CHROMEOS)
-  google_util::chromeos::ClearBrandForCurrentSession();
-#endif
 }
 
-void TemplateURLServiceTestUtil::TearDown() {
-  if (profile_.get()) {
-    // Clear the request context so it will get deleted. This should be done
-    // before shutting down the I/O thread to avoid memory leaks.
-    profile_->ResetRequestContext();
-    profile_.reset();
-  }
-
-  // Wait for the delete of the request context to happen.
-  if (io_thread_.IsRunning())
-    TemplateURLServiceTestUtil::BlockTillIOThreadProcessesRequests();
-
-  // The I/O thread must be shutdown before the DB thread.
-  io_thread_.Stop();
-
-  // Note that we must ensure the DB thread is stopped after WDS
-  // shutdown (so it can commit pending transactions) but before
-  // deleting the test profile directory, otherwise we may not be
-  // able to delete it due to an open transaction.
-  // Schedule another task on the DB thread to notify us that it's safe to
-  // carry on with the test.
-  base::WaitableEvent done(false, false);
-  BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
-      base::Bind(&base::WaitableEvent::Signal, base::Unretained(&done)));
-  done.Wait();
-  base::MessageLoop::current()->PostTask(FROM_HERE,
-                                         base::MessageLoop::QuitClosure());
-  base::MessageLoop::current()->Run();
-  db_thread_.Stop();
-
-  UIThreadSearchTermsData::SetGoogleBaseURL(std::string());
-
-  // Flush the message loop to make application verifiers happy.
-  message_loop_.RunUntilIdle();
-}
-
-void TemplateURLServiceTestUtil::OnTemplateURLServiceChanged() {
+void TemplateURLServiceTestUtilBase::OnTemplateURLServiceChanged() {
   changed_count_++;
 }
 
-int TemplateURLServiceTestUtil::GetObserverCount() {
+int TemplateURLServiceTestUtilBase::GetObserverCount() {
   return changed_count_;
 }
 
-void TemplateURLServiceTestUtil::ResetObserverCount() {
+void TemplateURLServiceTestUtilBase::ResetObserverCount() {
   changed_count_ = 0;
 }
 
-void TemplateURLServiceTestUtil::BlockTillServiceProcessesRequests() {
+void TemplateURLServiceTestUtilBase::BlockTillServiceProcessesRequests() {
   WaitForThreadToProcessRequests(BrowserThread::DB);
 }
 
-void TemplateURLServiceTestUtil::BlockTillIOThreadProcessesRequests() {
+void TemplateURLServiceTestUtilBase::BlockTillIOThreadProcessesRequests() {
   WaitForThreadToProcessRequests(BrowserThread::IO);
 }
 
-void TemplateURLServiceTestUtil::VerifyLoad() {
+void TemplateURLServiceTestUtilBase::VerifyLoad() {
   ASSERT_FALSE(model()->loaded());
   model()->Load();
   BlockTillServiceProcessesRequests();
@@ -176,47 +134,48 @@
   ResetObserverCount();
 }
 
-void TemplateURLServiceTestUtil::ChangeModelToLoadState() {
+void TemplateURLServiceTestUtilBase::ChangeModelToLoadState() {
   model()->ChangeToLoadedState();
   // Initialize the web data service so that the database gets updated with
   // any changes made.
 
-  model()->service_ = WebDataService::FromBrowserContext(profile_.get());
+  model()->service_ = WebDataService::FromBrowserContext(profile());
   BlockTillServiceProcessesRequests();
 }
 
-void TemplateURLServiceTestUtil::ClearModel() {
+void TemplateURLServiceTestUtilBase::ClearModel() {
   TemplateURLServiceFactory::GetInstance()->SetTestingFactory(
-      profile_.get(), NULL);
+      profile(), NULL);
 }
 
-void TemplateURLServiceTestUtil::ResetModel(bool verify_load) {
+void TemplateURLServiceTestUtilBase::ResetModel(bool verify_load) {
   TemplateURLServiceFactory::GetInstance()->SetTestingFactoryAndUse(
-      profile_.get(), TestingTemplateURLService::Build);
+      profile(), TestingTemplateURLService::Build);
   model()->AddObserver(this);
   changed_count_ = 0;
   if (verify_load)
     VerifyLoad();
 }
 
-string16 TemplateURLServiceTestUtil::GetAndClearSearchTerm() {
+string16 TemplateURLServiceTestUtilBase::GetAndClearSearchTerm() {
   return
       static_cast<TestingTemplateURLService*>(model())->GetAndClearSearchTerm();
 }
 
-void TemplateURLServiceTestUtil::SetGoogleBaseURL(const GURL& base_url) const {
+void TemplateURLServiceTestUtilBase::SetGoogleBaseURL(
+    const GURL& base_url) const {
   DCHECK(base_url.is_valid());
-  UIThreadSearchTermsData data(profile_.get());
+  UIThreadSearchTermsData data(profile());
   GoogleURLTracker::UpdatedDetails urls(GURL(data.GoogleBaseURLValue()),
                                         base_url);
   UIThreadSearchTermsData::SetGoogleBaseURL(base_url.spec());
   content::NotificationService::current()->Notify(
       chrome::NOTIFICATION_GOOGLE_URL_UPDATED,
-      content::Source<Profile>(profile_.get()),
+      content::Source<Profile>(profile()),
       content::Details<GoogleURLTracker::UpdatedDetails>(&urls));
 }
 
-void TemplateURLServiceTestUtil::SetManagedDefaultSearchPreferences(
+void TemplateURLServiceTestUtilBase::SetManagedDefaultSearchPreferences(
     bool enabled,
     const std::string& name,
     const std::string& keyword,
@@ -226,7 +185,7 @@
     const std::string& encodings,
     const std::string& alternate_url,
     const std::string& search_terms_replacement_key) {
-  TestingPrefServiceSyncable* pref_service = profile_->GetTestingPrefService();
+  TestingPrefServiceSyncable* pref_service = profile()->GetTestingPrefService();
   pref_service->SetManagedPref(prefs::kDefaultSearchProviderEnabled,
                                Value::CreateBooleanValue(enabled));
   pref_service->SetManagedPref(prefs::kDefaultSearchProviderName,
@@ -252,8 +211,8 @@
                    content::NotificationService::NoDetails());
 }
 
-void TemplateURLServiceTestUtil::RemoveManagedDefaultSearchPreferences() {
-  TestingPrefServiceSyncable* pref_service = profile_->GetTestingPrefService();
+void TemplateURLServiceTestUtilBase::RemoveManagedDefaultSearchPreferences() {
+  TestingPrefServiceSyncable* pref_service = profile()->GetTestingPrefService();
   pref_service->RemoveManagedPref(prefs::kDefaultSearchProviderEnabled);
   pref_service->RemoveManagedPref(prefs::kDefaultSearchProviderName);
   pref_service->RemoveManagedPref(prefs::kDefaultSearchProviderKeyword);
@@ -271,8 +230,69 @@
                    content::NotificationService::NoDetails());
 }
 
-TemplateURLService* TemplateURLServiceTestUtil::model() const {
-  return TemplateURLServiceFactory::GetForProfile(profile_.get());
+TemplateURLService* TemplateURLServiceTestUtilBase::model() const {
+  return TemplateURLServiceFactory::GetForProfile(profile());
+}
+
+
+// TemplateURLServiceTestUtil -------------------------------------------------
+
+TemplateURLServiceTestUtil::TemplateURLServiceTestUtil()
+    : ui_thread_(BrowserThread::UI, &message_loop_),
+      db_thread_(BrowserThread::DB),
+      io_thread_(BrowserThread::IO) {
+}
+
+TemplateURLServiceTestUtil::~TemplateURLServiceTestUtil() {
+}
+
+void TemplateURLServiceTestUtil::SetUp() {
+  // Make unique temp directory.
+  ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+  profile_.reset(new TestingProfile(temp_dir_.path()));
+  db_thread_.Start();
+
+  TemplateURLServiceTestUtilBase::CreateTemplateUrlService();
+
+#if defined(OS_CHROMEOS)
+  google_util::chromeos::ClearBrandForCurrentSession();
+#endif
+}
+
+void TemplateURLServiceTestUtil::TearDown() {
+  if (profile_.get()) {
+    // Clear the request context so it will get deleted. This should be done
+    // before shutting down the I/O thread to avoid memory leaks.
+    profile_->ResetRequestContext();
+    profile_.reset();
+  }
+
+  // Wait for the delete of the request context to happen.
+  if (io_thread_.IsRunning())
+    TemplateURLServiceTestUtilBase::BlockTillIOThreadProcessesRequests();
+
+  // The I/O thread must be shutdown before the DB thread.
+  io_thread_.Stop();
+
+  // Note that we must ensure the DB thread is stopped after WDS
+  // shutdown (so it can commit pending transactions) but before
+  // deleting the test profile directory, otherwise we may not be
+  // able to delete it due to an open transaction.
+  // Schedule another task on the DB thread to notify us that it's safe to
+  // carry on with the test.
+  base::WaitableEvent done(false, false);
+  BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
+      base::Bind(&base::WaitableEvent::Signal, base::Unretained(&done)));
+  done.Wait();
+  base::MessageLoop::current()->PostTask(FROM_HERE,
+                                         base::MessageLoop::QuitClosure());
+  base::MessageLoop::current()->Run();
+  db_thread_.Stop();
+
+  UIThreadSearchTermsData::SetGoogleBaseURL(std::string());
+
+  // Flush the message loop to make application verifiers happy.
+  message_loop_.RunUntilIdle();
 }
 
 TestingProfile* TemplateURLServiceTestUtil::profile() const {
diff --git a/chrome/browser/search_engines/template_url_service_test_util.h b/chrome/browser/search_engines/template_url_service_test_util.h
index ba8375f..7ddd4fd 100644
--- a/chrome/browser/search_engines/template_url_service_test_util.h
+++ b/chrome/browser/search_engines/template_url_service_test_util.h
@@ -24,21 +24,14 @@
 class TestingProfile;
 class WebDataService;
 
-// Implements functionality to make it easier to test TemplateURLService and
-// make changes to it.
-class TemplateURLServiceTestUtil : public TemplateURLServiceObserver {
+// TemplateURLServiceTestUtilBase contains basic API to ease testing of
+// TemplateURLService. User should take care of the infrastructure separately.
+class TemplateURLServiceTestUtilBase : public TemplateURLServiceObserver {
  public:
-  TemplateURLServiceTestUtil();
+  TemplateURLServiceTestUtilBase();
+  virtual ~TemplateURLServiceTestUtilBase();
 
-  virtual ~TemplateURLServiceTestUtil();
-
-  // Sets up the data structures for this class (mirroring gtest standard
-  // methods).
-  void SetUp();
-
-  // Cleans up data structures for this class  (mirroring gtest standard
-  // methods).
-  void TearDown();
+  void CreateTemplateUrlService();
 
   // TemplateURLServiceObserver implemementation.
   virtual void OnTemplateURLServiceChanged() OVERRIDE;
@@ -82,15 +75,15 @@
   // notification. If |alternate_url| is empty, uses an empty list of alternate
   // URLs, otherwise use a list containing a single entry.
   void SetManagedDefaultSearchPreferences(
-    bool enabled,
-    const std::string& name,
-    const std::string& keyword,
-    const std::string& search_url,
-    const std::string& suggest_url,
-    const std::string& icon_url,
-    const std::string& encodings,
-    const std::string& alternate_url,
-    const std::string& search_terms_replacement_key);
+      bool enabled,
+      const std::string& name,
+      const std::string& keyword,
+      const std::string& search_url,
+      const std::string& suggest_url,
+      const std::string& icon_url,
+      const std::string& encodings,
+      const std::string& alternate_url,
+      const std::string& search_terms_replacement_key);
 
   // Remove all the managed preferences for the default search provider and
   // trigger notification.
@@ -100,7 +93,31 @@
   TemplateURLService* model() const;
 
   // Returns the TestingProfile.
-  TestingProfile* profile() const;
+  virtual TestingProfile* profile() const = 0;
+
+ private:
+  int changed_count_;
+
+  DISALLOW_COPY_AND_ASSIGN(TemplateURLServiceTestUtilBase);
+};
+
+// TemplateURLServiceTestUtil sets up TestingProfile, TemplateURLService and
+// required threads.
+class TemplateURLServiceTestUtil : public TemplateURLServiceTestUtilBase {
+ public:
+  TemplateURLServiceTestUtil();
+  virtual ~TemplateURLServiceTestUtil();
+
+  // Sets up the data structures for this class (mirroring gtest standard
+  // methods).
+  void SetUp();
+
+  // Cleans up data structures for this class  (mirroring gtest standard
+  // methods).
+  void TearDown();
+
+  // Returns the TestingProfile.
+  virtual TestingProfile* profile() const OVERRIDE;
 
   // Starts an I/O thread.
   void StartIOThread();
@@ -116,7 +133,6 @@
   content::TestBrowserThread db_thread_;
   content::TestBrowserThread io_thread_;
   scoped_ptr<TestingProfile> profile_;
-  int changed_count_;
   base::ScopedTempDir temp_dir_;
 
   DISALLOW_COPY_AND_ASSIGN(TemplateURLServiceTestUtil);
diff --git a/chrome/browser/search_engines/template_url_service_unittest.cc b/chrome/browser/search_engines/template_url_service_unittest.cc
index 94026be..b1e95de 100644
--- a/chrome/browser/search_engines/template_url_service_unittest.cc
+++ b/chrome/browser/search_engines/template_url_service_unittest.cc
@@ -13,6 +13,7 @@
 #include "base/test/mock_time_provider.h"
 #include "base/threading/thread.h"
 #include "base/time/time.h"
+#include "chrome/browser/extensions/extension_service_unittest.h"
 #include "chrome/browser/history/history_notifications.h"
 #include "chrome/browser/history/history_service.h"
 #include "chrome/browser/history/history_service_factory.h"
@@ -23,6 +24,8 @@
 #include "chrome/browser/search_engines/template_url_service.h"
 #include "chrome/browser/search_engines/template_url_service_test_util.h"
 #include "chrome/browser/webdata/web_data_service_factory.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/extension_manifest_constants.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/webdata/common/web_database.h"
@@ -149,7 +152,103 @@
   history::VisitVector visits;
 };
 
-};  // namespace
+TemplateURL* AddKeywordWithDate(
+    TemplateURLService* model,
+    const std::string& short_name,
+    const std::string& keyword,
+    const std::string& url,
+    const std::string& suggest_url,
+    const std::string& alternate_url,
+    const std::string& favicon_url,
+    bool safe_for_autoreplace,
+    const std::string& encodings,
+    Time date_created,
+    Time last_modified) {
+  TemplateURLData data;
+  data.short_name = UTF8ToUTF16(short_name);
+  data.SetKeyword(UTF8ToUTF16(keyword));
+  data.SetURL(url);
+  data.suggestions_url = suggest_url;
+  if (!alternate_url.empty())
+    data.alternate_urls.push_back(alternate_url);
+  data.favicon_url = GURL(favicon_url);
+  data.safe_for_autoreplace = safe_for_autoreplace;
+  base::SplitString(encodings, ';', &data.input_encodings);
+  data.date_created = date_created;
+  data.last_modified = last_modified;
+  TemplateURL* t_url = new TemplateURL(model->profile(), data);
+  model->Add(t_url);
+  EXPECT_NE(0, t_url->id());
+  return t_url;
+}
+
+// Checks that the two TemplateURLs are similar. It does not check the id, the
+// date_created or the last_modified time.  Neither pointer should be NULL.
+void ExpectSimilar(const TemplateURL* expected, const TemplateURL* actual) {
+  ASSERT_TRUE(expected != NULL);
+  ASSERT_TRUE(actual != NULL);
+  EXPECT_EQ(expected->short_name(), actual->short_name());
+  EXPECT_EQ(expected->keyword(), actual->keyword());
+  EXPECT_EQ(expected->url(), actual->url());
+  EXPECT_EQ(expected->suggestions_url(), actual->suggestions_url());
+  EXPECT_EQ(expected->favicon_url(), actual->favicon_url());
+  EXPECT_EQ(expected->alternate_urls(), actual->alternate_urls());
+  EXPECT_EQ(expected->show_in_default_list(), actual->show_in_default_list());
+  EXPECT_EQ(expected->safe_for_autoreplace(), actual->safe_for_autoreplace());
+  EXPECT_EQ(expected->input_encodings(), actual->input_encodings());
+  EXPECT_EQ(expected->search_terms_replacement_key(),
+            actual->search_terms_replacement_key());
+}
+
+}  // namespace
+
+
+// TemplateURLServiceExtensionTest --------------------------------------------
+
+class TemplateURLServiceExtensionTest : public ExtensionServiceTestBase,
+                                        public TemplateURLServiceTestUtilBase {
+ public:
+  TemplateURLServiceExtensionTest();
+  virtual ~TemplateURLServiceExtensionTest();
+
+  // ExtensionServiceTestBase:
+  virtual void SetUp() OVERRIDE;
+
+  // TemplateURLServiceTestUtilBase:
+  virtual TestingProfile* profile() const OVERRIDE;
+
+  void CheckExtensionKeyword(const string16& keyword, const string16& name);
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TemplateURLServiceExtensionTest);
+};
+
+TemplateURLServiceExtensionTest::TemplateURLServiceExtensionTest() {}
+
+TemplateURLServiceExtensionTest::~TemplateURLServiceExtensionTest() {}
+
+void TemplateURLServiceExtensionTest::SetUp() {
+  ExtensionServiceTestBase::SetUp();
+  ExtensionServiceInitParams params;
+  InitializeExtensionService(params);
+  TemplateURLServiceTestUtilBase::CreateTemplateUrlService();
+}
+
+
+TestingProfile* TemplateURLServiceExtensionTest::profile() const {
+  return profile_.get();
+}
+
+void TemplateURLServiceExtensionTest::CheckExtensionKeyword(
+    const string16& keyword, const string16& name) {
+#if !defined(OS_ANDROID)
+  TemplateURL* ext_url =
+      model()->GetTemplateURLForKeyword(keyword);
+  ASSERT_TRUE(ext_url);
+  EXPECT_EQ(keyword, ext_url->keyword());
+  EXPECT_EQ(name, ext_url->short_name());
+#endif
+}
 
 
 // TemplateURLServiceTest -----------------------------------------------------
@@ -176,10 +275,6 @@
   // Verifies the two TemplateURLs are equal.
   void AssertEquals(const TemplateURL& expected, const TemplateURL& actual);
 
-  // Checks that the two TemplateURLs are similar. It does not check the id, the
-  // date_created or the last_modified time.  Neither pointer should be NULL.
-  void ExpectSimilar(const TemplateURL* expected, const TemplateURL* actual);
-
   // Create an URL that appears to have been prepopulated, but won't be in the
   // current data. The caller owns the returned TemplateURL*.
   TemplateURL* CreatePreloadedTemplateURL(bool safe_for_autoreplace,
@@ -233,22 +328,9 @@
     const std::string& encodings,
     Time date_created,
     Time last_modified) {
-  TemplateURLData data;
-  data.short_name = UTF8ToUTF16(short_name);
-  data.SetKeyword(UTF8ToUTF16(keyword));
-  data.SetURL(url);
-  data.suggestions_url = suggest_url;
-  if (!alternate_url.empty())
-    data.alternate_urls.push_back(alternate_url);
-  data.favicon_url = GURL(favicon_url);
-  data.safe_for_autoreplace = safe_for_autoreplace;
-  base::SplitString(encodings, ';', &data.input_encodings);
-  data.date_created = date_created;
-  data.last_modified = last_modified;
-  TemplateURL* t_url = new TemplateURL(test_util_.profile(), data);
-  model()->Add(t_url);
-  EXPECT_NE(0, t_url->id());
-  return t_url;
+  return ::AddKeywordWithDate(model(), short_name, keyword, url, suggest_url,
+                              alternate_url, favicon_url, safe_for_autoreplace,
+                              encodings, date_created, last_modified);
 }
 
 void TemplateURLServiceTest::AssertEquals(const TemplateURL& expected,
@@ -270,23 +352,6 @@
             actual.search_terms_replacement_key());
 }
 
-void TemplateURLServiceTest::ExpectSimilar(const TemplateURL* expected,
-                                           const TemplateURL* actual) {
-  ASSERT_TRUE(expected != NULL);
-  ASSERT_TRUE(actual != NULL);
-  EXPECT_EQ(expected->short_name(), actual->short_name());
-  EXPECT_EQ(expected->keyword(), actual->keyword());
-  EXPECT_EQ(expected->url(), actual->url());
-  EXPECT_EQ(expected->suggestions_url(), actual->suggestions_url());
-  EXPECT_EQ(expected->favicon_url(), actual->favicon_url());
-  EXPECT_EQ(expected->alternate_urls(), actual->alternate_urls());
-  EXPECT_EQ(expected->show_in_default_list(), actual->show_in_default_list());
-  EXPECT_EQ(expected->safe_for_autoreplace(), actual->safe_for_autoreplace());
-  EXPECT_EQ(expected->input_encodings(), actual->input_encodings());
-  EXPECT_EQ(expected->search_terms_replacement_key(),
-            actual->search_terms_replacement_key());
-}
-
 TemplateURL* TemplateURLServiceTest::CreatePreloadedTemplateURL(
     bool safe_for_autoreplace,
     int prepopulate_id) {
@@ -913,43 +978,68 @@
   AssertEquals(*cloned_url, *model()->GetDefaultSearchProvider());
 }
 
-TEST_F(TemplateURLServiceTest, ResetNonExtensionURLs) {
-  test_util_.VerifyLoad();
+TEST_F(TemplateURLServiceExtensionTest, ResetURLs) {
+  VerifyLoad();
 
   TemplateURL* new_provider = AddKeywordWithDate(
-      "short_name", "keyword", "http://test.com/search?t={searchTerms}",
+      model(), "short_name", "keyword", "http://test.com/search?t={searchTerms}",
       std::string(), std::string(), std::string(),
       true, "UTF-8", Time(), Time());
   model()->SetDefaultSearchProvider(new_provider);
   AddKeywordWithDate(
-      "extension1", "ext_keyword",
+      model(), "extension1", "ext_keyword",
       std::string(extensions::kExtensionScheme) + "://test1", std::string(),
       std::string(), std::string(), false, "UTF-8", Time(), Time());
+  AddKeywordWithDate(
+      model(), "extension2", "ext_keyword2",
+      std::string(extensions::kExtensionScheme) + "://test2", std::string(),
+      std::string(), std::string(), false, "UTF-8", Time(), Time());
   TemplateURL* default_provider = model()->GetDefaultSearchProvider();
   EXPECT_NE(SEARCH_ENGINE_GOOGLE,
       TemplateURLPrepopulateData::GetEngineType(default_provider->url()));
 
-  // Non-extension URLs should go away. Default search engine is Google again.
-  model()->ResetNonExtensionURLs();
+  DictionaryValue manifest;
+  manifest.SetString(extension_manifest_keys::kVersion, "1.0.0.0");
+  manifest.SetString(extension_manifest_keys::kName, "ext1");
+  manifest.SetString("app.launch.web_url", "http://www.google.com");
+  manifest.SetString(extension_manifest_keys::kOmniboxKeyword, "ext_keyword");
+  std::string error;
+  scoped_refptr<extensions::Extension> extension =
+      extensions::Extension::Create(
+          base::FilePath(FILE_PATH_LITERAL("//nonexistent")),
+          extensions::Manifest::COMPONENT,
+          manifest,
+          extensions::Extension::NO_FLAGS,
+          &error);
+  EXPECT_TRUE(extension.get() != NULL) << error;
+  ExtensionService* extension_service = profile()->GetExtensionService();
+  ASSERT_TRUE(extension_service);
+  extension_service->AddExtension(extension.get());
+  // All URLs except |extension_keywords| should go away. Default search engine
+  // is Google again.
+  model()->ResetURLs();
+
   default_provider = model()->GetDefaultSearchProvider();
   ASSERT_TRUE(default_provider);
   EXPECT_EQ(SEARCH_ENGINE_GOOGLE,
       TemplateURLPrepopulateData::GetEngineType(default_provider->url()));
-  EXPECT_TRUE(model()->GetTemplateURLForKeyword(ASCIIToUTF16("ext_keyword")));
+  CheckExtensionKeyword(ASCIIToUTF16("ext_keyword"), ASCIIToUTF16("ext1"));
+  EXPECT_FALSE(model()->GetTemplateURLForKeyword(ASCIIToUTF16("ext_keyword2")));
   EXPECT_FALSE(model()->GetTemplateURLForKeyword(ASCIIToUTF16("keyword")));
 
   // Reload URLs. Result should be the same, as extension keywords are now
   // persisted.
-  test_util_.ResetModel(true);
+  ResetModel(true);
   default_provider = model()->GetDefaultSearchProvider();
   ASSERT_TRUE(default_provider);
   EXPECT_EQ(SEARCH_ENGINE_GOOGLE,
       TemplateURLPrepopulateData::GetEngineType(default_provider->url()));
-  EXPECT_TRUE(model()->GetTemplateURLForKeyword(ASCIIToUTF16("ext_keyword")));
+  CheckExtensionKeyword(ASCIIToUTF16("ext_keyword"), ASCIIToUTF16("ext1"));
+  EXPECT_FALSE(model()->GetTemplateURLForKeyword(ASCIIToUTF16("ext_keyword2")));
   EXPECT_FALSE(model()->GetTemplateURLForKeyword(ASCIIToUTF16("keyword")));
 }
 
-TEST_F(TemplateURLServiceTest, ResetURLsWithManagedDefault) {
+TEST_F(TemplateURLServiceExtensionTest, ResetURLsWithManagedDefault) {
   // Set a managed preference that establishes a default search provider.
   const char kName[] = "test1";
   const char kKeyword[] = "test.com";
@@ -958,12 +1048,12 @@
   const char kEncodings[] = "UTF-16;UTF-32";
   const char kAlternateURL[] = "http://test.com/search#t={searchTerms}";
   const char kSearchTermsReplacementKey[] = "espv";
-  test_util_.SetManagedDefaultSearchPreferences(true, kName, kKeyword,
-                                                kSearchURL, std::string(),
-                                                kIconURL, kEncodings,
-                                                kAlternateURL,
-                                                kSearchTermsReplacementKey);
-  test_util_.VerifyLoad();
+  SetManagedDefaultSearchPreferences(true, kName, kKeyword,
+                                     kSearchURL, std::string(),
+                                     kIconURL, kEncodings,
+                                     kAlternateURL,
+                                     kSearchTermsReplacementKey);
+  VerifyLoad();
   // Verify that the default manager we are getting is the managed one.
   TemplateURLData data;
   data.short_name = ASCIIToUTF16(kName);
@@ -974,16 +1064,15 @@
   base::SplitString(kEncodings, ';', &data.input_encodings);
   data.alternate_urls.push_back(kAlternateURL);
   data.search_terms_replacement_key = kSearchTermsReplacementKey;
-  Profile* profile = test_util_.profile();
-  scoped_ptr<TemplateURL> expected_managed_default(new TemplateURL(profile,
-                                                                    data));
+  scoped_ptr<TemplateURL> expected_managed_default(new TemplateURL(profile(),
+                                                                   data));
   EXPECT_TRUE(model()->is_default_search_managed());
   const TemplateURL* actual_managed_default =
       model()->GetDefaultSearchProvider();
   ExpectSimilar(expected_managed_default.get(), actual_managed_default);
 
   // The following call has no effect on the managed search engine.
-  model()->ResetNonExtensionURLs();
+  model()->ResetURLs();
 
   EXPECT_TRUE(model()->is_default_search_managed());
   actual_managed_default = model()->GetDefaultSearchProvider();
diff --git a/chrome/browser/sessions/persistent_tab_restore_service_browsertest.cc b/chrome/browser/sessions/persistent_tab_restore_service_browsertest.cc
index 84c63a2..1840bd0 100644
--- a/chrome/browser/sessions/persistent_tab_restore_service_browsertest.cc
+++ b/chrome/browser/sessions/persistent_tab_restore_service_browsertest.cc
@@ -32,7 +32,6 @@
 #include "content/public/test/test_utils.h"
 #include "content/public/test/web_contents_tester.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/WebKit/public/web/WebKit.h"
 
 typedef TabRestoreService::Tab Tab;
 typedef TabRestoreService::Window Window;
@@ -79,7 +78,6 @@
 
   // testing::Test:
   virtual void SetUp() OVERRIDE {
-    WebKit::initialize(webkit_platform_support_.Get());
     ChromeRenderViewHostTestHarness::SetUp();
     time_factory_ = new PersistentTabRestoreTimeFactory();
     service_.reset(new PersistentTabRestoreService(profile(), time_factory_));
@@ -90,7 +88,6 @@
     service_.reset();
     delete time_factory_;
     ChromeRenderViewHostTestHarness::TearDown();
-    WebKit::shutdown();
   }
 
   TabRestoreService::Entries* mutable_entries() {
@@ -171,8 +168,6 @@
   std::string user_agent_override_;
   scoped_ptr<PersistentTabRestoreService> service_;
   PersistentTabRestoreTimeFactory* time_factory_;
-  content::RenderViewTest::RendererWebKitPlatformSupportImplNoSandbox
-      webkit_platform_support_;
 };
 
 namespace {
diff --git a/chrome/browser/sessions/session_restore_browsertest.cc b/chrome/browser/sessions/session_restore_browsertest.cc
index 59945a7..6154185 100644
--- a/chrome/browser/sessions/session_restore_browsertest.cc
+++ b/chrome/browser/sessions/session_restore_browsertest.cc
@@ -50,6 +50,10 @@
 #include "base/mac/scoped_nsautorelease_pool.h"
 #endif
 
+#if defined(OS_WIN) && defined(USE_ASH)
+#include "base/win/windows_version.h"
+#endif
+
 class SessionRestoreTest : public InProcessBrowserTest {
  public:
   SessionRestoreTest() : active_browser_list_(NULL) {}
@@ -851,6 +855,12 @@
 // If this test flakes, use http://crbug.com/29110
 IN_PROC_BROWSER_TEST_F(SessionRestoreTest,
                        RestoreAfterClosingTabbedBrowserWithAppAndLaunching) {
+#if defined(OS_WIN) && defined(USE_ASH)
+  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
+  if (base::win::GetVersion() >= base::win::VERSION_WIN8)
+    return;
+#endif
+
   ui_test_utils::NavigateToURL(browser(), url1_);
 
   // Launch an app.
@@ -1073,18 +1083,18 @@
   ui_test_utils::NavigateToURL(browser(), url1_);
   content::NavigationController* controller =
       &browser()->tab_strip_model()->GetActiveWebContents()->GetController();
-  ASSERT_TRUE(controller->GetSessionStorageNamespace());
+  ASSERT_TRUE(controller->GetDefaultSessionStorageNamespace());
   std::string session_storage_persistent_id =
-      controller->GetSessionStorageNamespace()->persistent_id();
+      controller->GetDefaultSessionStorageNamespace()->persistent_id();
   Browser* new_browser = QuitBrowserAndRestore(browser(), 1);
   ASSERT_EQ(1u, active_browser_list_->size());
   ASSERT_EQ(url1_,
             new_browser->tab_strip_model()->GetActiveWebContents()->GetURL());
   content::NavigationController* new_controller =
       &new_browser->tab_strip_model()->GetActiveWebContents()->GetController();
-  ASSERT_TRUE(new_controller->GetSessionStorageNamespace());
+  ASSERT_TRUE(new_controller->GetDefaultSessionStorageNamespace());
   std::string restored_session_storage_persistent_id =
-      new_controller->GetSessionStorageNamespace()->persistent_id();
+      new_controller->GetDefaultSessionStorageNamespace()->persistent_id();
   EXPECT_EQ(session_storage_persistent_id,
             restored_session_storage_persistent_id);
 }
@@ -1095,12 +1105,15 @@
   {
     content::NavigationController* controller =
         &browser()->tab_strip_model()->GetActiveWebContents()->GetController();
-    ASSERT_TRUE(controller->GetSessionStorageNamespace());
+    ASSERT_TRUE(controller->GetDefaultSessionStorageNamespace());
 
+    content::SessionStorageNamespaceMap session_storage_namespace_map;
+    session_storage_namespace_map[std::string()] =
+        controller->GetDefaultSessionStorageNamespace();
     scoped_ptr<content::WebContents> web_contents(
         content::WebContents::CreateWithSessionStorage(
             content::WebContents::CreateParams(browser()->profile()),
-            controller->GetSessionStorageNamespace()));
+            session_storage_namespace_map));
 
     TabStripModel* tab_strip_model = browser()->tab_strip_model();
     scoped_ptr<content::WebContents> old_web_contents(
@@ -1115,7 +1128,7 @@
   content::NavigationController* controller =
       &browser()->tab_strip_model()->GetActiveWebContents()->GetController();
   EXPECT_TRUE(
-      controller->GetSessionStorageNamespace()->should_persist());
+      controller->GetDefaultSessionStorageNamespace()->should_persist());
 
   // Quit and restore. Check that no extra tabs were created.
   Browser* new_browser = QuitBrowserAndRestore(browser(), 1);
diff --git a/chrome/browser/sessions/session_service.cc b/chrome/browser/sessions/session_service.cc
index 05bf038..dd97f43 100644
--- a/chrome/browser/sessions/session_service.cc
+++ b/chrome/browser/sessions/session_service.cc
@@ -1334,7 +1334,7 @@
 
   // Record the association between the sessionStorage namespace and the tab.
   content::SessionStorageNamespace* session_storage_namespace =
-      tab->GetController().GetSessionStorageNamespace();
+      tab->GetController().GetDefaultSessionStorageNamespace();
   ScheduleCommand(CreateSessionStorageAssociatedCommand(
       session_tab_helper->session_id(),
       session_storage_namespace->persistent_id()));
@@ -1736,8 +1736,12 @@
 
   // Record the association between the SessionStorageNamespace and the
   // tab.
+  //
+  // TODO(ajwong): This should be processing the whole map rather than
+  // just the default. This in particular will not work for tabs with only
+  // isolated apps which won't have a default partition.
   content::SessionStorageNamespace* session_storage_namespace =
-      contents->GetController().GetSessionStorageNamespace();
+      contents->GetController().GetDefaultSessionStorageNamespace();
   ScheduleCommand(CreateSessionStorageAssociatedCommand(
       session_tab_helper->session_id(),
       session_storage_namespace->persistent_id()));
@@ -1748,7 +1752,7 @@
   // Allow the associated sessionStorage to get deleted; it won't be needed
   // in the session restore.
   content::SessionStorageNamespace* session_storage_namespace =
-      contents->GetController().GetSessionStorageNamespace();
+      contents->GetController().GetDefaultSessionStorageNamespace();
   session_storage_namespace->SetShouldPersist(false);
   SessionTabHelper* session_tab_helper =
       SessionTabHelper::FromWebContents(contents);
diff --git a/chrome/browser/sessions/tab_restore_service_helper.cc b/chrome/browser/sessions/tab_restore_service_helper.cc
index 2782b47..2b13861 100644
--- a/chrome/browser/sessions/tab_restore_service_helper.cc
+++ b/chrome/browser/sessions/tab_restore_service_helper.cc
@@ -419,7 +419,9 @@
   tab->user_agent_override =
       controller->GetWebContents()->GetUserAgentOverride();
 
-  tab->session_storage_namespace = controller->GetSessionStorageNamespace();
+  // TODO(ajwong): This does not correctly handle storage for isolated apps.
+  tab->session_storage_namespace =
+      controller->GetDefaultSessionStorageNamespace();
 
   // Delegate may be NULL during unit tests.
   if (delegate) {
diff --git a/chrome/browser/signin/android_profile_oauth2_token_service.cc b/chrome/browser/signin/android_profile_oauth2_token_service.cc
index 8516a87..f79eb63 100644
--- a/chrome/browser/signin/android_profile_oauth2_token_service.cc
+++ b/chrome/browser/signin/android_profile_oauth2_token_service.cc
@@ -13,7 +13,6 @@
 #include "chrome/browser/sync/profile_sync_service_android.h"
 #include "content/public/browser/browser_thread.h"
 #include "jni/AndroidProfileOAuth2TokenServiceHelper_jni.h"
-#include "net/url_request/url_request_context_getter.h"
 
 using base::android::AttachCurrentThread;
 using base::android::CheckException;
@@ -39,9 +38,7 @@
 
 }  // namespace
 
-AndroidProfileOAuth2TokenService::AndroidProfileOAuth2TokenService(
-    net::URLRequestContextGetter* getter)
-    : ProfileOAuth2TokenService(getter) {
+AndroidProfileOAuth2TokenService::AndroidProfileOAuth2TokenService() {
 }
 
 AndroidProfileOAuth2TokenService::~AndroidProfileOAuth2TokenService() {
diff --git a/chrome/browser/signin/android_profile_oauth2_token_service.h b/chrome/browser/signin/android_profile_oauth2_token_service.h
index 22c805b..39680fe 100644
--- a/chrome/browser/signin/android_profile_oauth2_token_service.h
+++ b/chrome/browser/signin/android_profile_oauth2_token_service.h
@@ -15,10 +15,6 @@
 #include "chrome/browser/signin/profile_oauth2_token_service.h"
 #include "google_apis/gaia/google_service_auth_error.h"
 
-namespace net {
-class URLRequestContextGetter;
-}
-
 class TokenService;
 
 
@@ -67,8 +63,7 @@
 
  protected:
   friend class ProfileOAuth2TokenServiceFactory;
-  explicit AndroidProfileOAuth2TokenService(
-      net::URLRequestContextGetter* getter);
+  AndroidProfileOAuth2TokenService();
   virtual ~AndroidProfileOAuth2TokenService();
 
   // virtual for testing.
diff --git a/chrome/browser/signin/oauth2_token_service.cc b/chrome/browser/signin/oauth2_token_service.cc
index e0b2414..1790aea 100644
--- a/chrome/browser/signin/oauth2_token_service.cc
+++ b/chrome/browser/signin/oauth2_token_service.cc
@@ -283,8 +283,7 @@
 OAuth2TokenService::Consumer::~Consumer() {
 }
 
-OAuth2TokenService::OAuth2TokenService(net::URLRequestContextGetter* getter)
-    : request_context_getter_(getter) {
+OAuth2TokenService::OAuth2TokenService() {
 }
 
 OAuth2TokenService::~OAuth2TokenService() {
@@ -342,7 +341,7 @@
 
   pending_fetchers_[fetch_parameters] =
       Fetcher::CreateAndStart(this,
-                              request_context_getter_.get(),
+                              GetRequestContext(),
                               refresh_token,
                               scopes,
                               request->AsWeakPtr());
diff --git a/chrome/browser/signin/oauth2_token_service.h b/chrome/browser/signin/oauth2_token_service.h
index f961505..b40066e 100644
--- a/chrome/browser/signin/oauth2_token_service.h
+++ b/chrome/browser/signin/oauth2_token_service.h
@@ -101,7 +101,7 @@
   // A set of scopes in OAuth2 authentication.
   typedef std::set<std::string> ScopeSet;
 
-  explicit OAuth2TokenService(net::URLRequestContextGetter* getter);
+  OAuth2TokenService();
   virtual ~OAuth2TokenService();
 
   // Add or remove observers of this token service.
@@ -188,6 +188,10 @@
   void FireRefreshTokensCleared();
 
  private:
+  // Derived classes must provide a request context used for fetching access
+  // tokens with the |StartRequest| method.
+  virtual net::URLRequestContextGetter* GetRequestContext() = 0;
+
   // Class that fetches an OAuth2 access token for a given set of scopes and
   // OAuth2 refresh token.
   class Fetcher;
@@ -215,9 +219,6 @@
   // Called when |fetcher| finishes fetching.
   void OnFetchComplete(Fetcher* fetcher);
 
-  // Getter to use for fetchers.
-  scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
-
   // The cache of currently valid tokens.
   typedef std::map<ScopeSet, CacheEntry> TokenCache;
   TokenCache token_cache_;
diff --git a/chrome/browser/signin/oauth2_token_service_unittest.cc b/chrome/browser/signin/oauth2_token_service_unittest.cc
index 901258b..6859f37 100644
--- a/chrome/browser/signin/oauth2_token_service_unittest.cc
+++ b/chrome/browser/signin/oauth2_token_service_unittest.cc
@@ -44,8 +44,8 @@
 
 class TestOAuth2TokenService : public OAuth2TokenService {
  public:
-  explicit TestOAuth2TokenService(net::URLRequestContextGetter* getter)
-      : OAuth2TokenService(getter) {
+  explicit TestOAuth2TokenService(net::TestURLRequestContextGetter* getter)
+      : request_context_getter_(getter) {
   }
 
   // For testing: set the refresh token to be used.
@@ -57,22 +57,24 @@
   virtual std::string GetRefreshToken() OVERRIDE { return refresh_token_; }
 
  private:
+  // OAuth2TokenService implementation.
+  virtual net::URLRequestContextGetter* GetRequestContext() OVERRIDE {
+    return request_context_getter_.get();
+  }
+
   std::string refresh_token_;
+  scoped_refptr<net::TestURLRequestContextGetter> request_context_getter_;
 };
 
 class OAuth2TokenServiceTest : public TokenServiceTestHarness {
  public:
-  OAuth2TokenServiceTest()
-      : request_context_getter_(new net::TestURLRequestContextGetter(
-            message_loop_.message_loop_proxy())) {
-  }
-
   virtual void SetUp() OVERRIDE {
     TokenServiceTestHarness::SetUp();
     io_thread_.reset(new content::TestBrowserThread(content::BrowserThread::IO,
                                                     &message_loop_));
     oauth2_service_.reset(
-        new TestOAuth2TokenService(request_context_getter_.get()));
+        new TestOAuth2TokenService(new net::TestURLRequestContextGetter(
+            message_loop_.message_loop_proxy())));
   }
 
   virtual void TearDown() OVERRIDE {
@@ -81,7 +83,6 @@
 
  protected:
   scoped_ptr<content::TestBrowserThread> io_thread_;
-  scoped_refptr<net::TestURLRequestContextGetter> request_context_getter_;
   net::TestURLFetcherFactory factory_;
   scoped_ptr<TestOAuth2TokenService> oauth2_service_;
   TestingOAuth2TokenServiceConsumer consumer_;
diff --git a/chrome/browser/signin/profile_oauth2_token_service.cc b/chrome/browser/signin/profile_oauth2_token_service.cc
index f846059..26b337f 100644
--- a/chrome/browser/signin/profile_oauth2_token_service.cc
+++ b/chrome/browser/signin/profile_oauth2_token_service.cc
@@ -35,10 +35,8 @@
 
 }  // namespace
 
-ProfileOAuth2TokenService::ProfileOAuth2TokenService(
-    net::URLRequestContextGetter* getter)
-    : OAuth2TokenService(getter),
-      profile_(NULL),
+ProfileOAuth2TokenService::ProfileOAuth2TokenService()
+    : profile_(NULL),
       last_auth_error_(GoogleServiceAuthError::NONE) {
 }
 
@@ -153,6 +151,10 @@
   return last_auth_error_;
 }
 
+net::URLRequestContextGetter* ProfileOAuth2TokenService::GetRequestContext() {
+  return profile_->GetRequestContext();
+}
+
 void ProfileOAuth2TokenService::RegisterCacheEntry(
     const std::string& refresh_token,
     const ScopeSet& scopes,
diff --git a/chrome/browser/signin/profile_oauth2_token_service.h b/chrome/browser/signin/profile_oauth2_token_service.h
index d5cbe9f..28ee5d5 100644
--- a/chrome/browser/signin/profile_oauth2_token_service.h
+++ b/chrome/browser/signin/profile_oauth2_token_service.h
@@ -56,6 +56,9 @@
   // SigninGlobalError::AuthStatusProvider implementation.
   virtual GoogleServiceAuthError GetAuthStatus() const OVERRIDE;
 
+  // OAuth2TokenService implementation.
+  virtual net::URLRequestContextGetter* GetRequestContext() OVERRIDE;
+
   // Takes injected TokenService for testing.
   bool ShouldCacheForRefreshToken(TokenService *token_service,
                                   const std::string& refresh_token);
@@ -72,7 +75,7 @@
 
  protected:
   friend class ProfileOAuth2TokenServiceFactory;
-  explicit ProfileOAuth2TokenService(net::URLRequestContextGetter* getter);
+  ProfileOAuth2TokenService();
   virtual ~ProfileOAuth2TokenService();
 
   // OAuth2TokenService overrides.
diff --git a/chrome/browser/signin/profile_oauth2_token_service_factory.cc b/chrome/browser/signin/profile_oauth2_token_service_factory.cc
index 92c88e6..e40433b 100644
--- a/chrome/browser/signin/profile_oauth2_token_service_factory.cc
+++ b/chrome/browser/signin/profile_oauth2_token_service_factory.cc
@@ -49,9 +49,9 @@
   Profile* profile = static_cast<Profile*>(context);
   ProfileOAuth2TokenService* service;
 #if defined(OS_ANDROID)
-  service = new AndroidProfileOAuth2TokenService(profile->GetRequestContext());
+  service = new AndroidProfileOAuth2TokenService();
 #else
-  service = new ProfileOAuth2TokenService(profile->GetRequestContext());
+  service = new ProfileOAuth2TokenService();
 #endif
   service->Initialize(profile);
   return service;
diff --git a/chrome/browser/signin/profile_oauth2_token_service_request_unittest.cc b/chrome/browser/signin/profile_oauth2_token_service_request_unittest.cc
index adcf700..ef1c18b 100644
--- a/chrome/browser/signin/profile_oauth2_token_service_request_unittest.cc
+++ b/chrome/browser/signin/profile_oauth2_token_service_request_unittest.cc
@@ -115,8 +115,7 @@
 }
 
 MockProfileOAuth2TokenService::MockProfileOAuth2TokenService()
-    : ProfileOAuth2TokenService(NULL /* URLRequestContextGetter */),
-      success_(true),
+    : success_(true),
       oauth2_access_token_(std::string("success token")) {
 }
 
diff --git a/chrome/browser/signin/signin_manager.cc b/chrome/browser/signin/signin_manager.cc
index d0629e5..f419d84 100644
--- a/chrome/browser/signin/signin_manager.cc
+++ b/chrome/browser/signin/signin_manager.cc
@@ -38,7 +38,7 @@
 #include "google_apis/gaia/gaia_urls.h"
 #include "net/base/escape.h"
 #include "net/url_request/url_request_context.h"
-#include "third_party/icu/public/i18n/unicode/regex.h"
+#include "third_party/icu/source/i18n/unicode/regex.h"
 
 using namespace signin_internals_util;
 
diff --git a/chrome/browser/ssl/ssl_tab_helper.cc b/chrome/browser/ssl/ssl_tab_helper.cc
index 802687e..9cb9fde 100644
--- a/chrome/browser/ssl/ssl_tab_helper.cc
+++ b/chrome/browser/ssl/ssl_tab_helper.cc
@@ -42,9 +42,9 @@
 
 class SSLCertResultInfoBarDelegate : public ConfirmInfoBarDelegate {
  public:
-  // Creates an SSL cert result delegate.  If |previous_infobar| is
+  // Creates an SSL cert result infobar delegate.  If |previous_infobar| is
   // NULL, adds the infobar to |infobar_service|; otherwise, replaces
-  // |previous_infobar|.  Returns the new delegate if it was successfully added.
+  // |previous_infobar|.  Returns the new infobar if it was successfully added.
   // |cert| is valid iff cert addition was successful.
   static InfoBarDelegate* Create(InfoBarService* infobar_service,
                                  InfoBarDelegate* previous_infobar,
@@ -137,7 +137,7 @@
   explicit SSLAddCertData(InfoBarService* infobar_service);
   virtual ~SSLAddCertData();
 
-  // Displays an infobar, replacing |infobar_delegate_| if it exists.
+  // Displays an infobar, replacing |infobar_| if it exists.
   void ShowInfoBar(const string16& message, net::X509Certificate* cert);
 
  private:
@@ -147,7 +147,7 @@
                        const content::NotificationDetails& details) OVERRIDE;
 
   InfoBarService* infobar_service_;
-  InfoBarDelegate* infobar_delegate_;
+  InfoBarDelegate* infobar_;
   content::NotificationRegistrar registrar_;
 
   DISALLOW_COPY_AND_ASSIGN(SSLAddCertData);
@@ -155,7 +155,7 @@
 
 SSLTabHelper::SSLAddCertData::SSLAddCertData(InfoBarService* infobar_service)
     : infobar_service_(infobar_service),
-      infobar_delegate_(NULL) {
+      infobar_(NULL) {
   content::Source<InfoBarService> source(infobar_service_);
   registrar_.Add(this, chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED,
                  source);
@@ -168,8 +168,8 @@
 
 void SSLTabHelper::SSLAddCertData::ShowInfoBar(const string16& message,
                                                net::X509Certificate* cert) {
-  infobar_delegate_ = SSLCertResultInfoBarDelegate::Create(
-      infobar_service_, infobar_delegate_, message, cert);
+  infobar_ = SSLCertResultInfoBarDelegate::Create(infobar_service_, infobar_,
+                                                  message, cert);
 }
 
 void SSLTabHelper::SSLAddCertData::Observe(
@@ -178,11 +178,11 @@
     const content::NotificationDetails& details) {
   DCHECK(type == chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED ||
          type == chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REPLACED);
-  if (infobar_delegate_ ==
+  if (infobar_ ==
       ((type == chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED) ?
           content::Details<InfoBarRemovedDetails>(details)->first :
           content::Details<InfoBarReplacedDetails>(details)->first))
-    infobar_delegate_ = NULL;
+    infobar_ = NULL;
 }
 
 
diff --git a/chrome/browser/status_icons/status_icon.cc b/chrome/browser/status_icons/status_icon.cc
index 00270d2..79efafc 100644
--- a/chrome/browser/status_icons/status_icon.cc
+++ b/chrome/browser/status_icons/status_icon.cc
@@ -29,6 +29,9 @@
   FOR_EACH_OBSERVER(StatusIconObserver, observers_, OnStatusIconClicked());
 }
 
+void StatusIcon::SetClickActionLabel(const string16& label) {
+}
+
 #if defined(OS_WIN)
 void StatusIcon::DispatchBalloonClickEvent() {
   FOR_EACH_OBSERVER(StatusIconObserver, observers_, OnBalloonClicked());
diff --git a/chrome/browser/status_icons/status_icon.h b/chrome/browser/status_icons/status_icon.h
index 8d846a5..6110c64 100644
--- a/chrome/browser/status_icons/status_icon.h
+++ b/chrome/browser/status_icons/status_icon.h
@@ -34,6 +34,12 @@
   // Sets the hover text for this status icon.
   virtual void SetToolTip(const string16& tool_tip) = 0;
 
+  // Sets the label for the menu item which is created as a replacement for the
+  // status icon click action on platforms that do not support custom click
+  // actions for the status icon (e.g. Ubuntu Unity). Since only a few platforms
+  // would need this, the default action is to ignore the call.
+  virtual void SetClickActionLabel(const string16& label);
+
   // Displays a notification balloon with the specified contents.
   // Depending on the platform it might not appear by the icon tray.
   virtual void DisplayBalloon(const gfx::ImageSkia& icon,
diff --git a/chrome/browser/status_icons/status_tray.cc b/chrome/browser/status_icons/status_tray.cc
index 3d99ad5..aaa7a57 100644
--- a/chrome/browser/status_icons/status_tray.cc
+++ b/chrome/browser/status_icons/status_tray.cc
@@ -11,8 +11,8 @@
 StatusTray::~StatusTray() {
 }
 
-StatusIcon* StatusTray::CreateStatusIcon() {
-  StatusIcon* icon = CreatePlatformStatusIcon();
+StatusIcon* StatusTray::CreateStatusIcon(StatusIconType type) {
+  StatusIcon* icon = CreatePlatformStatusIcon(type);
   if (icon)
     status_icons_.push_back(icon);
   return icon;
diff --git a/chrome/browser/status_icons/status_tray.h b/chrome/browser/status_icons/status_tray.h
index c715ec5..e4f240d 100644
--- a/chrome/browser/status_icons/status_tray.h
+++ b/chrome/browser/status_icons/status_tray.h
@@ -15,6 +15,14 @@
 // APIs to add/remove icons to the tray and attach context menus.
 class StatusTray {
  public:
+  enum StatusIconType {
+    NOTIFICATION_TRAY_ICON = 0,
+    MEDIA_STREAM_CAPTURE_ICON,
+    BACKGROUND_MODE_ICON,
+    OTHER_ICON,
+    NAMED_STATUS_ICON_COUNT
+  };
+
   // Static factory method that is implemented separately for each platform to
   // produce the appropriate platform-specific instance. Returns NULL if this
   // platform does not support status icons.
@@ -24,7 +32,7 @@
 
   // Creates a new StatusIcon. The StatusTray retains ownership of the
   // StatusIcon. Returns NULL if the StatusIcon could not be created.
-  StatusIcon* CreateStatusIcon();
+  StatusIcon* CreateStatusIcon(StatusIconType type);
 
   // Removes |icon| from this status tray.
   void RemoveStatusIcon(StatusIcon* icon);
@@ -35,14 +43,12 @@
   StatusTray();
 
   // Factory method for creating a status icon for this platform.
-  virtual StatusIcon* CreatePlatformStatusIcon() = 0;
+  virtual StatusIcon* CreatePlatformStatusIcon(StatusIconType type) = 0;
 
   // Returns the list of active status icons so subclasses can operate on them.
   const StatusIcons& status_icons() const { return status_icons_; }
 
  private:
-  FRIEND_TEST_ALL_PREFIXES(StatusTrayTest, CreateRemove);
-
   // List containing all active StatusIcons. The icons are owned by this
   // StatusTray.
   StatusIcons status_icons_;
diff --git a/chrome/browser/status_icons/status_tray_unittest.cc b/chrome/browser/status_icons/status_tray_unittest.cc
index 818a4fa..a71fa9a 100644
--- a/chrome/browser/status_icons/status_tray_unittest.cc
+++ b/chrome/browser/status_icons/status_tray_unittest.cc
@@ -24,25 +24,28 @@
 
 class TestStatusTray : public StatusTray {
  public:
-  MOCK_METHOD0(CreatePlatformStatusIcon, StatusIcon*());
+  MOCK_METHOD1(CreatePlatformStatusIcon,
+               StatusIcon*(StatusTray::StatusIconType type));
   MOCK_METHOD1(UpdatePlatformContextMenu, void(ui::MenuModel*));
+
+  const StatusIcons& GetStatusIconsForTest() const { return status_icons(); }
 };
 
 TEST(StatusTrayTest, Create) {
   // Check for creation and leaks.
   TestStatusTray tray;
-  EXPECT_CALL(tray,
-      CreatePlatformStatusIcon()).WillOnce(Return(new MockStatusIcon()));
-  tray.CreateStatusIcon();
+  EXPECT_CALL(tray, CreatePlatformStatusIcon(StatusTray::OTHER_ICON)).WillOnce(
+      Return(new MockStatusIcon()));
+  tray.CreateStatusIcon(StatusTray::OTHER_ICON);
 }
 
 // Make sure that removing an icon removes it from the list.
 TEST(StatusTrayTest, CreateRemove) {
   TestStatusTray tray;
-  EXPECT_CALL(tray,
-      CreatePlatformStatusIcon()).WillOnce(Return(new MockStatusIcon()));
-  StatusIcon* icon = tray.CreateStatusIcon();
-  EXPECT_EQ(1U, tray.status_icons_.size());
+  EXPECT_CALL(tray, CreatePlatformStatusIcon(StatusTray::OTHER_ICON)).WillOnce(
+      Return(new MockStatusIcon()));
+  StatusIcon* icon = tray.CreateStatusIcon(StatusTray::OTHER_ICON);
+  EXPECT_EQ(1U, tray.GetStatusIconsForTest().size());
   tray.RemoveStatusIcon(icon);
-  EXPECT_EQ(0U, tray.status_icons_.size());
+  EXPECT_EQ(0U, tray.GetStatusIconsForTest().size());
 }
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 d6be33d..a259ef1 100644
--- a/chrome/browser/storage_monitor/image_capture_device_manager_unittest.mm
+++ b/chrome/browser/storage_monitor/image_capture_device_manager_unittest.mm
@@ -15,6 +15,7 @@
 #include "chrome/browser/storage_monitor/image_capture_device.h"
 #include "chrome/browser/storage_monitor/image_capture_device_manager.h"
 #include "chrome/browser/storage_monitor/test_storage_monitor.h"
+#include "chrome/test/base/testing_browser_process.h"
 #include "content/public/test/test_browser_thread.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -257,6 +258,8 @@
   virtual void SetUp() OVERRIDE {
     ui_thread_.reset(new content::TestBrowserThread(
         content::BrowserThread::UI, &message_loop_));
+
+    monitor_ = chrome::test::TestStorageMonitor::CreateAndInstall();
   }
 
   MockICCameraDevice* AttachDevice(
@@ -278,28 +281,29 @@
  protected:
   base::MessageLoopForUI message_loop_;
   scoped_ptr<content::TestBrowserThread> ui_thread_;
-  chrome::test::TestStorageMonitor monitor_;
+
+  chrome::test::TestStorageMonitor* monitor_;
   TestCameraListener listener_;
 };
 
 TEST_F(ImageCaptureDeviceManagerTest, TestAttachDetach) {
   chrome::ImageCaptureDeviceManager manager;
-  manager.SetNotifications(monitor_.receiver());
+  manager.SetNotifications(monitor_->receiver());
   ICCameraDevice* device = AttachDevice(&manager);
   std::vector<chrome::StorageInfo> devices =
-      monitor_.GetAllAvailableStorages();
+      monitor_->GetAllAvailableStorages();
 
   ASSERT_EQ(1U, devices.size());
   EXPECT_EQ(std::string("ic:") + kDeviceId, devices[0].device_id());
 
   DetachDevice(&manager, device);
-  devices = monitor_.GetAllAvailableStorages();
+  devices = monitor_->GetAllAvailableStorages();
   ASSERT_EQ(0U, devices.size());
 };
 
 TEST_F(ImageCaptureDeviceManagerTest, OpenCamera) {
   chrome::ImageCaptureDeviceManager manager;
-  manager.SetNotifications(monitor_.receiver());
+  manager.SetNotifications(monitor_->receiver());
   ICCameraDevice* device = AttachDevice(&manager);
 
   EXPECT_FALSE(chrome::ImageCaptureDeviceManager::deviceForUUID(
@@ -335,7 +339,7 @@
 
 TEST_F(ImageCaptureDeviceManagerTest, RemoveCamera) {
   chrome::ImageCaptureDeviceManager manager;
-  manager.SetNotifications(monitor_.receiver());
+  manager.SetNotifications(monitor_->receiver());
   ICCameraDevice* device = AttachDevice(&manager);
 
   base::scoped_nsobject<ImageCaptureDevice> camera(
@@ -354,7 +358,7 @@
           content::BrowserThread::FILE, &message_loop_));
 
   chrome::ImageCaptureDeviceManager manager;
-  manager.SetNotifications(monitor_.receiver());
+  manager.SetNotifications(monitor_->receiver());
   MockICCameraDevice* device = AttachDevice(&manager);
 
   base::scoped_nsobject<ImageCaptureDevice> camera(
@@ -410,7 +414,7 @@
           content::BrowserThread::FILE, &message_loop_));
 
   chrome::ImageCaptureDeviceManager manager;
-  manager.SetNotifications(monitor_.receiver());
+  manager.SetNotifications(monitor_->receiver());
   MockICCameraDevice* device = AttachDevice(&manager);
 
   base::scoped_nsobject<ImageCaptureDevice> camera(
diff --git a/chrome/browser/storage_monitor/media_storage_util_unittest.cc b/chrome/browser/storage_monitor/media_storage_util_unittest.cc
index 12fd336..4ed217e 100644
--- a/chrome/browser/storage_monitor/media_storage_util_unittest.cc
+++ b/chrome/browser/storage_monitor/media_storage_util_unittest.cc
@@ -13,6 +13,7 @@
 #include "chrome/browser/storage_monitor/removable_device_constants.h"
 #include "chrome/browser/storage_monitor/storage_monitor.h"
 #include "chrome/browser/storage_monitor/test_storage_monitor.h"
+#include "chrome/test/base/testing_browser_process.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/test/test_browser_thread.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -47,7 +48,7 @@
                      const string16& name,
                      const base::FilePath::StringType& location) {
     StorageInfo info(id, name, location, string16(), string16(), string16(), 0);
-    monitor_.receiver()->ProcessAttach(info);
+    monitor_->receiver()->ProcessAttach(info);
   }
 
  protected:
@@ -62,11 +63,12 @@
   }
 
   virtual void SetUp() OVERRIDE {
+    monitor_ = chrome::test::TestStorageMonitor::CreateAndInstall();
     ASSERT_TRUE(scoped_temp_dir_.CreateUniqueTempDir());
     file_thread_.Start();
   }
 
-  virtual void TearDown() {
+  virtual void TearDown() OVERRIDE {
     WaitForFileThread();
   }
 
@@ -86,7 +88,7 @@
   base::MessageLoop message_loop_;
 
  private:
-  chrome::test::TestStorageMonitor monitor_;
+  chrome::test::TestStorageMonitor* monitor_;
   content::TestBrowserThread ui_thread_;
   content::TestBrowserThread file_thread_;
   base::ScopedTempDir scoped_temp_dir_;
diff --git a/chrome/browser/storage_monitor/media_transfer_protocol_device_observer_linux_unittest.cc b/chrome/browser/storage_monitor/media_transfer_protocol_device_observer_linux_unittest.cc
index 4a1827b..c895cee 100644
--- a/chrome/browser/storage_monitor/media_transfer_protocol_device_observer_linux_unittest.cc
+++ b/chrome/browser/storage_monitor/media_transfer_protocol_device_observer_linux_unittest.cc
@@ -12,10 +12,12 @@
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/browser_process.h"
 #include "chrome/browser/storage_monitor/mock_removable_storage_observer.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/test/base/testing_browser_process.h"
 #include "content/public/test/test_browser_thread.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -92,13 +94,16 @@
  protected:
   virtual void SetUp() OVERRIDE {
     mock_storage_observer_.reset(new MockRemovableStorageObserver);
+    chrome::test::TestStorageMonitor* monitor =
+        chrome::test::TestStorageMonitor::CreateAndInstall();
     mtp_device_observer_.reset(
-        new TestMediaTransferProtocolDeviceObserverLinux(monitor_.receiver()));
-    monitor_.AddObserver(mock_storage_observer_.get());
+        new TestMediaTransferProtocolDeviceObserverLinux(monitor->receiver()));
+    monitor->AddObserver(mock_storage_observer_.get());
   }
 
   virtual void TearDown() OVERRIDE {
-    monitor_.RemoveObserver(mock_storage_observer_.get());
+    StorageMonitor* monitor = g_browser_process->storage_monitor();
+    monitor->RemoveObserver(mock_storage_observer_.get());
     mtp_device_observer_.reset();
   }
 
@@ -115,7 +120,6 @@
   base::MessageLoop message_loop_;
   content::TestBrowserThread file_thread_;
 
-  chrome::test::TestStorageMonitor monitor_;
   scoped_ptr<TestMediaTransferProtocolDeviceObserverLinux> mtp_device_observer_;
   scoped_ptr<MockRemovableStorageObserver> mock_storage_observer_;
 
diff --git a/chrome/browser/storage_monitor/storage_monitor.cc b/chrome/browser/storage_monitor/storage_monitor.cc
index a771fd5..10d043e 100644
--- a/chrome/browser/storage_monitor/storage_monitor.cc
+++ b/chrome/browser/storage_monitor/storage_monitor.cc
@@ -6,13 +6,12 @@
 
 #include "base/stl_util.h"
 #include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/browser_process.h"
 #include "chrome/browser/storage_monitor/removable_storage_observer.h"
 #include "chrome/browser/storage_monitor/transient_device_ids.h"
 
 namespace chrome {
 
-static StorageMonitor* g_storage_monitor = NULL;
-
 StorageMonitor::Receiver::~Receiver() {
 }
 
@@ -46,7 +45,10 @@
 }
 
 StorageMonitor* StorageMonitor::GetInstance() {
-  return g_storage_monitor;
+  if (g_browser_process)
+    return g_browser_process->storage_monitor();
+
+  return NULL;
 }
 
 std::vector<StorageInfo> StorageMonitor::GetAllAvailableStorages() const {
@@ -117,18 +119,9 @@
       initialized_(false),
       transient_device_ids_(new TransientDeviceIds) {
   receiver_.reset(new ReceiverImpl(this));
-
-  DCHECK(!g_storage_monitor);
-  g_storage_monitor = this;
 }
 
 StorageMonitor::~StorageMonitor() {
-  g_storage_monitor = NULL;
-}
-
-// static
-void StorageMonitor::RemoveSingletonForTesting() {
-  g_storage_monitor = NULL;
 }
 
 StorageMonitor::Receiver* StorageMonitor::receiver() const {
diff --git a/chrome/browser/storage_monitor/storage_monitor.h b/chrome/browser/storage_monitor/storage_monitor.h
index 9258dd4..9d20d60 100644
--- a/chrome/browser/storage_monitor/storage_monitor.h
+++ b/chrome/browser/storage_monitor/storage_monitor.h
@@ -14,7 +14,6 @@
 #include "base/observer_list_threadsafe.h"
 #include "base/strings/string16.h"
 #include "base/synchronization/lock.h"
-#include "base/threading/thread_checker.h"
 #include "chrome/browser/storage_monitor/storage_info.h"
 
 class ChromeBrowserMainPartsLinux;
@@ -37,8 +36,8 @@
 
 // Base class for platform-specific instances watching for removable storage
 // attachments/detachments.
-// Lifecycle contracts: This class is created by ChromeBrowserMain
-// implementations before the profile is initialized, so listeners can be
+// Lifecycle contracts: This class is created in the browser process
+// before the profile is initialized, so listeners can be
 // created during profile construction. The platform-specific initialization,
 // which can lead to calling registered listeners with notifications of
 // attached volumes, are done lazily at first use through the async
@@ -70,10 +69,18 @@
     EJECT_FAILURE
   };
 
-  // Returns a pointer to an object owned by the BrowserMainParts, with lifetime
-  // somewhat shorter than a process Singleton.
+  // Returns a pointer to a newly created per-platform object with the
+  // StorageMonitor interface.
+  static StorageMonitor* Create();
+
+  // Returns a pointer to an object owned by BrowserProcess, with lifetime
+  // starting before main message loop start, and ending after main message loop
+  // shutdown. Called outside it's lifetime (or with no browser process),
+  // returns NULL.
   static StorageMonitor* GetInstance();
 
+  virtual ~StorageMonitor();
+
   // 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
@@ -135,11 +142,6 @@
   friend class ::SystemInfoStorageEjectApiTest;
 
   StorageMonitor();
-  virtual ~StorageMonitor();
-
-  // Removes the existing singleton for testing.
-  // (So that a new one can be created.)
-  static void RemoveSingletonForTesting();
 
   virtual Receiver* receiver() const;
 
diff --git a/chrome/browser/storage_monitor/storage_monitor_chromeos.cc b/chrome/browser/storage_monitor/storage_monitor_chromeos.cc
index c61f530..a871fa8 100644
--- a/chrome/browser/storage_monitor/storage_monitor_chromeos.cc
+++ b/chrome/browser/storage_monitor/storage_monitor_chromeos.cc
@@ -307,3 +307,11 @@
 }
 
 }  // namespace chromeos
+
+namespace chrome {
+
+StorageMonitor* StorageMonitor::Create() {
+  return new chromeos::StorageMonitorCros();
+}
+
+}  // namespace chrome
diff --git a/chrome/browser/storage_monitor/storage_monitor_chromeos_unittest.cc b/chrome/browser/storage_monitor/storage_monitor_chromeos_unittest.cc
index 67302fd..f972c87 100644
--- a/chrome/browser/storage_monitor/storage_monitor_chromeos_unittest.cc
+++ b/chrome/browser/storage_monitor/storage_monitor_chromeos_unittest.cc
@@ -16,6 +16,8 @@
 #include "chrome/browser/storage_monitor/removable_device_constants.h"
 #include "chrome/browser/storage_monitor/storage_info.h"
 #include "chrome/browser/storage_monitor/test_media_transfer_protocol_manager_linux.h"
+#include "chrome/browser/storage_monitor/test_storage_monitor.h"
+#include "chrome/test/base/testing_browser_process.h"
 #include "chromeos/disks/mock_disk_mount_manager.h"
 #include "content/public/test/test_browser_thread.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -135,7 +137,7 @@
 
   base::MessageLoop ui_loop_;
 
-  scoped_ptr<TestStorageMonitorCros> monitor_;
+  TestStorageMonitorCros* monitor_;
 
   // Owned by DiskMountManager.
   disks::MockDiskMountManager* disk_mount_manager_mock_;
@@ -176,14 +178,20 @@
   mock_storage_observer_.reset(new chrome::MockRemovableStorageObserver);
 
   // Initialize the test subject.
-  monitor_.reset(new TestStorageMonitorCros());
+  chrome::test::TestStorageMonitor::RemoveSingleton();
+  monitor_ = new TestStorageMonitorCros();
+  scoped_ptr<chrome::StorageMonitor> pass_monitor(monitor_);
+  TestingBrowserProcess* browser_process = TestingBrowserProcess::GetGlobal();
+  DCHECK(browser_process);
+  browser_process->SetStorageMonitor(pass_monitor.Pass());
+
   monitor_->Init();
   monitor_->AddObserver(mock_storage_observer_.get());
 }
 
 void StorageMonitorCrosTest::TearDown() {
   monitor_->RemoveObserver(mock_storage_observer_.get());
-  monitor_.reset();
+  monitor_ = NULL;
 
   disk_mount_manager_mock_ = NULL;
   DiskMountManager::Shutdown();
diff --git a/chrome/browser/storage_monitor/storage_monitor_linux.cc b/chrome/browser/storage_monitor/storage_monitor_linux.cc
index 6435529..f2154ed 100644
--- a/chrome/browser/storage_monitor/storage_monitor_linux.cc
+++ b/chrome/browser/storage_monitor/storage_monitor_linux.cc
@@ -513,4 +513,9 @@
   receiver()->ProcessAttach(*storage_info);
 }
 
+StorageMonitor* StorageMonitor::Create() {
+  const base::FilePath kDefaultMtabPath("/etc/mtab");
+  return new StorageMonitorLinux(kDefaultMtabPath);
+}
+
 }  // namespace chrome
diff --git a/chrome/browser/storage_monitor/storage_monitor_linux_unittest.cc b/chrome/browser/storage_monitor/storage_monitor_linux_unittest.cc
index 4c87e3d..1a19918 100644
--- a/chrome/browser/storage_monitor/storage_monitor_linux_unittest.cc
+++ b/chrome/browser/storage_monitor/storage_monitor_linux_unittest.cc
@@ -23,6 +23,8 @@
 #include "chrome/browser/storage_monitor/storage_info.h"
 #include "chrome/browser/storage_monitor/storage_monitor.h"
 #include "chrome/browser/storage_monitor/test_media_transfer_protocol_manager_linux.h"
+#include "chrome/browser/storage_monitor/test_storage_monitor.h"
+#include "chrome/test/base/testing_browser_process.h"
 #include "content/public/test/test_browser_thread.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -181,8 +183,13 @@
                 arraysize(initial_test_data),
                 true  /* overwrite */);
 
-    // Initialize the test subject.
-    monitor_.reset(new TestStorageMonitorLinux(mtab_file_, &message_loop_));
+    test::TestStorageMonitor::RemoveSingleton();
+    monitor_ = new TestStorageMonitorLinux(mtab_file_, &message_loop_);
+    scoped_ptr<StorageMonitor> pass_monitor(monitor_);
+    TestingBrowserProcess* browser_process = TestingBrowserProcess::GetGlobal();
+    DCHECK(browser_process);
+    browser_process->SetStorageMonitor(pass_monitor.Pass());
+
     mock_storage_observer_.reset(new MockRemovableStorageObserver);
     monitor_->AddObserver(mock_storage_observer_.get());
 
@@ -193,8 +200,10 @@
   virtual void TearDown() OVERRIDE {
     base::RunLoop().RunUntilIdle();
     monitor_->RemoveObserver(mock_storage_observer_.get());
-    monitor_.reset();
     base::RunLoop().RunUntilIdle();
+
+    // Linux storage monitor must be destroyed on the UI thread, so do it here.
+    test::TestStorageMonitor::RemoveSingleton();
   }
 
   // Append mtab entries from the |data| array of size |data_size| to the mtab
@@ -243,7 +252,7 @@
   }
 
   StorageMonitor* notifier() {
-    return monitor_.get();
+    return monitor_;
   }
 
   uint64 GetStorageSize(const base::FilePath& path) {
@@ -316,7 +325,7 @@
   // Path to the test mtab file.
   base::FilePath mtab_file_;
 
-  scoped_ptr<TestStorageMonitorLinux> monitor_;
+  TestStorageMonitorLinux* monitor_;
 
   DISALLOW_COPY_AND_ASSIGN(StorageMonitorLinuxTest);
 };
diff --git a/chrome/browser/storage_monitor/storage_monitor_mac.mm b/chrome/browser/storage_monitor/storage_monitor_mac.mm
index 346f958..f642864 100644
--- a/chrome/browser/storage_monitor/storage_monitor_mac.mm
+++ b/chrome/browser/storage_monitor/storage_monitor_mac.mm
@@ -369,4 +369,8 @@
   return false;
 }
 
+StorageMonitor* StorageMonitor::Create() {
+  return new StorageMonitorMac();
+}
+
 }  // namespace chrome
diff --git a/chrome/browser/storage_monitor/storage_monitor_mac_unittest.mm b/chrome/browser/storage_monitor/storage_monitor_mac_unittest.mm
index b8c584f..ec3f7ff 100644
--- a/chrome/browser/storage_monitor/storage_monitor_mac_unittest.mm
+++ b/chrome/browser/storage_monitor/storage_monitor_mac_unittest.mm
@@ -14,6 +14,8 @@
 #include "chrome/browser/storage_monitor/mock_removable_storage_observer.h"
 #include "chrome/browser/storage_monitor/removable_device_constants.h"
 #include "chrome/browser/storage_monitor/storage_info.h"
+#include "chrome/browser/storage_monitor/test_storage_monitor.h"
+#include "chrome/test/base/testing_browser_process.h"
 #include "content/public/test/test_browser_thread.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -44,7 +46,12 @@
   }
 
   virtual void SetUp() OVERRIDE {
-    monitor_.reset(new StorageMonitorMac);
+    test::TestStorageMonitor::RemoveSingleton();
+    monitor_ = new StorageMonitorMac;
+    scoped_ptr<StorageMonitor> pass_monitor(monitor_);
+    TestingBrowserProcess* browser_process = TestingBrowserProcess::GetGlobal();
+    DCHECK(browser_process);
+    browser_process->SetStorageMonitor(pass_monitor.Pass());
 
     mock_storage_observer_.reset(new MockRemovableStorageObserver);
     monitor_->AddObserver(mock_storage_observer_.get());
@@ -60,7 +67,7 @@
   void UpdateDisk(StorageInfo info, StorageMonitorMac::UpdateType update_type) {
     content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
         base::Bind(&StorageMonitorMac::UpdateDisk,
-                   base::Unretained(monitor_.get()),
+                   base::Unretained(monitor_),
                    "dummy_bsd_name", info, update_type));
     base::RunLoop().RunUntilIdle();
   }
@@ -79,7 +86,7 @@
   std::string device_id_;
   StorageInfo disk_info_;
 
-  scoped_ptr<StorageMonitorMac> monitor_;
+  StorageMonitorMac* monitor_;
 };
 
 TEST_F(StorageMonitorMacTest, AddRemove) {
diff --git a/chrome/browser/storage_monitor/storage_monitor_unittest.cc b/chrome/browser/storage_monitor/storage_monitor_unittest.cc
index 50a3a4a..a98ec54 100644
--- a/chrome/browser/storage_monitor/storage_monitor_unittest.cc
+++ b/chrome/browser/storage_monitor/storage_monitor_unittest.cc
@@ -10,22 +10,31 @@
 #include "chrome/browser/storage_monitor/test_storage_monitor.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+namespace {
+
+void SetLatch(bool* called) {
+  *called = true;
+}
+
+}  // namespace
+
 namespace chrome {
 
 TEST(StorageMonitorTest, TestInitialize) {
+  test::TestStorageMonitor::RemoveSingleton();
   test::TestStorageMonitor monitor;
   EXPECT_FALSE(monitor.init_called_);
 
-  base::WaitableEvent event(false, false);
-  monitor.EnsureInitialized(base::Bind(&base::WaitableEvent::Signal,
-                                       base::Unretained(&event)));
+  bool initialized = false;
+  monitor.EnsureInitialized(base::Bind(&SetLatch, &initialized));
   EXPECT_TRUE(monitor.init_called_);
-  EXPECT_FALSE(event.IsSignaled());
+  EXPECT_FALSE(initialized);
   monitor.MarkInitialized();
-  EXPECT_TRUE(event.IsSignaled());
+  EXPECT_TRUE(initialized);
 }
 
 TEST(StorageMonitorTest, DeviceAttachDetachNotifications) {
+  test::TestStorageMonitor::RemoveSingleton();
   base::MessageLoop message_loop;
   const string16 kDeviceName = ASCIIToUTF16("media device");
   const std::string kDeviceId1 = "dcim:UUID:FFF0-0001";
@@ -73,6 +82,7 @@
 }
 
 TEST(StorageMonitorTest, GetAllAvailableStoragesEmpty) {
+  test::TestStorageMonitor::RemoveSingleton();
   base::MessageLoop message_loop;
   test::TestStorageMonitor monitor;
   std::vector<StorageInfo> devices = monitor.GetAllAvailableStorages();
@@ -80,6 +90,7 @@
 }
 
 TEST(StorageMonitorTest, GetAllAvailableStorageAttachDetach) {
+  test::TestStorageMonitor::RemoveSingleton();
   base::MessageLoop message_loop;
   test::TestStorageMonitor monitor;
   const std::string kDeviceId1 = "dcim:UUID:FFF0-0042";
diff --git a/chrome/browser/storage_monitor/storage_monitor_win.cc b/chrome/browser/storage_monitor/storage_monitor_win.cc
index 4fcc8f6..beec36d 100644
--- a/chrome/browser/storage_monitor/storage_monitor_win.cc
+++ b/chrome/browser/storage_monitor/storage_monitor_win.cc
@@ -18,12 +18,6 @@
 
 // StorageMonitorWin -------------------------------------------------------
 
-// static
-StorageMonitorWin* StorageMonitorWin::Create() {
-  return new StorageMonitorWin(new VolumeMountWatcherWin(),
-                               new PortableDeviceWatcherWin());
-}
-
 StorageMonitorWin::StorageMonitorWin(
     VolumeMountWatcherWin* volume_mount_watcher,
     PortableDeviceWatcherWin* portable_device_watcher)
@@ -167,4 +161,9 @@
   portable_device_watcher_->OnWindowMessage(event_type, data);
 }
 
+StorageMonitor* StorageMonitor::Create() {
+  return new StorageMonitorWin(new VolumeMountWatcherWin(),
+                               new PortableDeviceWatcherWin());
+}
+
 }  // namespace chrome
diff --git a/chrome/browser/storage_monitor/storage_monitor_win.h b/chrome/browser/storage_monitor/storage_monitor_win.h
index 6472c0d..c036fbb 100644
--- a/chrome/browser/storage_monitor/storage_monitor_win.h
+++ b/chrome/browser/storage_monitor/storage_monitor_win.h
@@ -25,10 +25,6 @@
 
 class StorageMonitorWin : public StorageMonitor {
  public:
-  // Creates an instance of StorageMonitorWin. Should only be called by browser
-  // start up code. Use GetInstance() instead.
-  static StorageMonitorWin* Create();
-
   virtual ~StorageMonitorWin();
 
   // Must be called after the file thread is created.
@@ -49,10 +45,11 @@
  private:
   class PortableDeviceNotifications;
   friend class test::TestStorageMonitorWin;
+  friend StorageMonitor* StorageMonitor::Create();
 
   // To support unit tests, this constructor takes |volume_mount_watcher| and
   // |portable_device_watcher| objects. These params are either constructed in
-  // unit tests or in StorageMonitorWin::Create() function.
+  // unit tests or in StorageMonitorWin Create() function.
   StorageMonitorWin(VolumeMountWatcherWin* volume_mount_watcher,
                     PortableDeviceWatcherWin* portable_device_watcher);
 
diff --git a/chrome/browser/storage_monitor/storage_monitor_win_unittest.cc b/chrome/browser/storage_monitor/storage_monitor_win_unittest.cc
index 12a742b..c23cb34 100644
--- a/chrome/browser/storage_monitor/storage_monitor_win_unittest.cc
+++ b/chrome/browser/storage_monitor/storage_monitor_win_unittest.cc
@@ -19,9 +19,11 @@
 #include "chrome/browser/storage_monitor/storage_info.h"
 #include "chrome/browser/storage_monitor/storage_monitor_win.h"
 #include "chrome/browser/storage_monitor/test_portable_device_watcher_win.h"
+#include "chrome/browser/storage_monitor/test_storage_monitor.h"
 #include "chrome/browser/storage_monitor/test_storage_monitor_win.h"
 #include "chrome/browser/storage_monitor/test_volume_mount_watcher_win.h"
 #include "chrome/browser/storage_monitor/volume_mount_watcher_win.h"
+#include "chrome/test/base/testing_browser_process.h"
 #include "content/public/test/test_browser_thread.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -63,7 +65,7 @@
                          base::string16* pnp_device_id,
                          base::string16* storage_object_id);
 
-  scoped_ptr<TestStorageMonitorWin> monitor_;
+  TestStorageMonitorWin* monitor_;
 
   // Weak pointer; owned by the device notifications class.
   TestVolumeMountWatcherWin* volume_mount_watcher_;
@@ -86,9 +88,15 @@
 
 void StorageMonitorWinTest::SetUp() {
   ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  test::TestStorageMonitor::RemoveSingleton();
   volume_mount_watcher_ = new TestVolumeMountWatcherWin;
-  monitor_.reset(new TestStorageMonitorWin(volume_mount_watcher_,
-                                           new TestPortableDeviceWatcherWin));
+  monitor_ = new TestStorageMonitorWin(volume_mount_watcher_,
+                                       new TestPortableDeviceWatcherWin);
+  scoped_ptr<StorageMonitor> pass_monitor(monitor_);
+  TestingBrowserProcess* browser_process = TestingBrowserProcess::GetGlobal();
+  DCHECK(browser_process);
+  browser_process->SetStorageMonitor(pass_monitor.Pass());
+
   monitor_->Init();
   RunUntilIdle();
   monitor_->AddObserver(&observer_);
@@ -98,11 +106,16 @@
   RunUntilIdle();
   monitor_->RemoveObserver(&observer_);
   volume_mount_watcher_->ShutdownWorkerPool();
-  monitor_.reset();
+  monitor_ = NULL;
+
+  // Windows storage monitor must be destroyed on the same thread
+  // as construction.
+  test::TestStorageMonitor::RemoveSingleton();
 }
 
 void StorageMonitorWinTest::PreAttachDevices() {
-  monitor_.reset();
+  test::TestStorageMonitor::RemoveSingleton();
+  monitor_ = NULL;
   volume_mount_watcher_ = new TestVolumeMountWatcherWin;
   volume_mount_watcher_->SetAttachedDevicesFake();
 
@@ -117,8 +130,13 @@
       expect_attach_calls++;
   }
 
-  monitor_.reset(new TestStorageMonitorWin(volume_mount_watcher_,
-                                           new TestPortableDeviceWatcherWin));
+  monitor_ = new TestStorageMonitorWin(volume_mount_watcher_,
+                                       new TestPortableDeviceWatcherWin);
+  scoped_ptr<StorageMonitor> pass_monitor(monitor_);
+  TestingBrowserProcess* browser_process = TestingBrowserProcess::GetGlobal();
+  DCHECK(browser_process);
+  browser_process->SetStorageMonitor(pass_monitor.Pass());
+
   monitor_->AddObserver(&observer_);
   monitor_->Init();
 
diff --git a/chrome/browser/storage_monitor/test_storage_monitor.cc b/chrome/browser/storage_monitor/test_storage_monitor.cc
index e28ce2c..22c3f7d 100644
--- a/chrome/browser/storage_monitor/test_storage_monitor.cc
+++ b/chrome/browser/storage_monitor/test_storage_monitor.cc
@@ -4,7 +4,12 @@
 
 #include "chrome/browser/storage_monitor/test_storage_monitor.h"
 
+#include "base/run_loop.h"
+#include "base/synchronization/waitable_event.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_impl.h"
 #include "chrome/browser/storage_monitor/storage_info.h"
+#include "chrome/test/base/testing_browser_process.h"
 
 #if defined(OS_LINUX)
 #include "chrome/browser/storage_monitor/test_media_transfer_protocol_manager_linux.h"
@@ -25,10 +30,52 @@
 
 TestStorageMonitor::~TestStorageMonitor() {}
 
-TestStorageMonitor*
-TestStorageMonitor::CreateForBrowserTests() {
-  StorageMonitor::RemoveSingletonForTesting();
-  return new TestStorageMonitor();
+TestStorageMonitor* TestStorageMonitor::CreateAndInstall() {
+  RemoveSingleton();
+  TestStorageMonitor* monitor = new TestStorageMonitor();
+  scoped_ptr<StorageMonitor> pass_monitor(monitor);
+  monitor->Init();
+  monitor->MarkInitialized();
+  TestingBrowserProcess* browser_process = TestingBrowserProcess::GetGlobal();
+  if (browser_process) {
+    browser_process->SetStorageMonitor(pass_monitor.Pass());
+    return monitor;
+  }
+  return NULL;
+}
+
+TestStorageMonitor* TestStorageMonitor::CreateForBrowserTests() {
+  TestStorageMonitor* return_monitor = new TestStorageMonitor();
+  return_monitor->Init();
+  return_monitor->MarkInitialized();
+
+  scoped_ptr<StorageMonitor> monitor(return_monitor);
+  BrowserProcessImpl* browser_process =
+      static_cast<BrowserProcessImpl*>(g_browser_process);
+  DCHECK(browser_process);
+  browser_process->set_storage_monitor_for_test(monitor.Pass());
+  return return_monitor;
+}
+
+void TestStorageMonitor::RemoveSingleton() {
+  TestingBrowserProcess* browser_process = TestingBrowserProcess::GetGlobal();
+  if (browser_process)
+    browser_process->SetStorageMonitor(scoped_ptr<StorageMonitor>());
+}
+
+// static
+void TestStorageMonitor::SyncInitialize() {
+  StorageMonitor* monitor = g_browser_process->storage_monitor();
+  if (monitor->IsInitialized())
+    return;
+
+  base::WaitableEvent event(true, false);
+  monitor->EnsureInitialized(base::Bind(&base::WaitableEvent::Signal,
+                             base::Unretained(&event)));
+  while (!event.IsSignaled()) {
+    base::RunLoop().RunUntilIdle();
+  }
+  DCHECK(monitor->IsInitialized());
 }
 
 void TestStorageMonitor::Init() {
diff --git a/chrome/browser/storage_monitor/test_storage_monitor.h b/chrome/browser/storage_monitor/test_storage_monitor.h
index 6408e66..26ff133 100644
--- a/chrome/browser/storage_monitor/test_storage_monitor.h
+++ b/chrome/browser/storage_monitor/test_storage_monitor.h
@@ -21,10 +21,21 @@
 
   void MarkInitialized();
 
-  // Will create a new testing implementation for browser tests,
-  // taking care to deal with the existing singleton correctly.
+  // Create and initialize a new TestStorageMonitor and install it
+  // in the TestingBrowserProcess.
+  static TestStorageMonitor* CreateAndInstall();
+
+  // Create and initialize a new TestStorageMonitor, and install it
+  // in the BrowserProcessImpl. (Browser tests use the production browser
+  // process implementation.)
   static TestStorageMonitor* CreateForBrowserTests();
 
+  // Remove the singleton StorageMonitor from the TestingBrowserProcess.
+  static void RemoveSingleton();
+
+  // Synchronously initialize the current storage monitor.
+  static void SyncInitialize();
+
   virtual bool GetStorageInfoForPath(
       const base::FilePath& path,
       StorageInfo* device_info) const OVERRIDE;
diff --git a/chrome/browser/sync/glue/android_invalidator_bridge_proxy_unittest.cc b/chrome/browser/sync/glue/android_invalidator_bridge_proxy_unittest.cc
deleted file mode 100644
index d3b9011..0000000
--- a/chrome/browser/sync/glue/android_invalidator_bridge_proxy_unittest.cc
+++ /dev/null
@@ -1,94 +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 <string>
-
-#include "base/memory/scoped_ptr.h"
-#include "base/threading/thread.h"
-#include "chrome/browser/sync/glue/android_invalidator_bridge.h"
-#include "chrome/test/base/profile_mock.h"
-#include "content/public/test/test_browser_thread.h"
-#include "sync/internal_api/public/base/model_type.h"
-#include "sync/internal_api/public/base/model_type_test_util.h"
-#include "sync/notifier/fake_invalidation_handler.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace syncer {
-class InvalidationStateTracker;
-}  // namespace syncer
-
-namespace browser_sync {
-
-namespace {
-
-// All tests just verify that each call is passed through to the delegate, with
-// the exception of RegisterHandler, UnregisterHandler, and
-// UpdateRegisteredIds, which also verifies the call is forwarded to the
-// bridge.
-class AndroidInvalidatorBridgeProxyTest : public testing::Test {
- public:
-  AndroidInvalidatorBridgeProxyTest()
-    : ui_thread_(content::BrowserThread::UI, &ui_loop_),
-      bridge_(&mock_profile_, ui_loop_.message_loop_proxy()),
-      invalidator_(new AndroidInvalidatorBridgeProxy(&bridge_)) {
-    // Pump |ui_loop_| to fully initialize |bridge_|.
-    ui_loop_.RunUntilIdle();
-  }
-
-  virtual ~AndroidInvalidatorBridgeProxyTest() {
-    DestroyInvalidator();
-  }
-
-  AndroidInvalidatorBridge* GetBridge() {
-    return &bridge_;
-  }
-
-  AndroidInvalidatorBridgeProxy* GetInvalidator() {
-    return invalidator_.get();
-  }
-
- protected:
-  void DestroyInvalidator() {
-    invalidator_.reset();
-    bridge_.StopForShutdown();
-    ui_loop_.RunUntilIdle();
-  }
-
-  base::MessageLoop ui_loop_;
-  content::TestBrowserThread ui_thread_;
-  ::testing::NiceMock<ProfileMock> mock_profile_;
-  AndroidInvalidatorBridge bridge_;
-  scoped_ptr<AndroidInvalidatorBridgeProxy> invalidator_;
-};
-
-TEST_F(AndroidInvalidatorBridgeProxyTest, HandlerMethods) {
-  syncer::ObjectIdSet ids;
-  ids.insert(invalidation::ObjectId(1, "id1"));
-
-  syncer::FakeInvalidationHandler handler;
-
-  GetInvalidator()->RegisterHandler(&handler);
-  EXPECT_TRUE(GetBridge()->IsHandlerRegisteredForTest(&handler));
-
-  GetInvalidator()->UpdateRegisteredIds(&handler, ids);
-  EXPECT_EQ(ids, GetBridge()->GetRegisteredIdsForTest(&handler));
-
-  GetInvalidator()->UnregisterHandler(&handler);
-  EXPECT_FALSE(GetBridge()->IsHandlerRegisteredForTest(&handler));
-}
-
-TEST_F(AndroidInvalidatorBridgeProxyTest, GetInvalidatorState) {
-  // The AndroidInvalidatorBridge never enters an error state.
-  EXPECT_EQ(syncer::INVALIDATIONS_ENABLED,
-            GetInvalidator()->GetInvalidatorState());
-  EXPECT_EQ(syncer::INVALIDATIONS_ENABLED,
-            GetBridge()->GetInvalidatorState());
-}
-
-}  // namespace
-}  // namespace browser_sync
-
diff --git a/chrome/browser/sync/glue/android_invalidator_bridge_unittest.cc b/chrome/browser/sync/glue/android_invalidator_bridge_unittest.cc
deleted file mode 100644
index 3fae404..0000000
--- a/chrome/browser/sync/glue/android_invalidator_bridge_unittest.cc
+++ /dev/null
@@ -1,190 +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 <cstddef>
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/compiler_specific.h"
-#include "base/location.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_proxy.h"
-#include "base/run_loop.h"
-#include "base/sequenced_task_runner.h"
-#include "base/threading/thread.h"
-#include "chrome/browser/chrome_notification_types.h"
-#include "chrome/test/base/profile_mock.h"
-#include "content/public/browser/notification_details.h"
-#include "content/public/browser/notification_service.h"
-#include "content/public/test/test_browser_thread.h"
-#include "sync/internal_api/public/base/model_type.h"
-#include "sync/internal_api/public/base/model_type_invalidation_map.h"
-#include "sync/notifier/fake_invalidation_handler.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"
-
-namespace browser_sync {
-namespace {
-
-using ::testing::NiceMock;
-
-// Since all the interesting stuff happens on the sync thread, we have
-// to be careful to use GTest/GMock only on the main thread since they
-// are not thread-safe.
-
-class AndroidInvalidatorBridgeTest : public testing::Test {
- public:
-  AndroidInvalidatorBridgeTest()
-      : ui_thread_(content::BrowserThread::UI, &ui_loop_),
-        sync_thread_("Sync thread"),
-        sync_handler_notification_success_(false) {}
-
-  virtual ~AndroidInvalidatorBridgeTest() {}
-
- protected:
-  virtual void SetUp() OVERRIDE {
-    ASSERT_TRUE(sync_thread_.Start());
-    bridge_.reset(
-        new AndroidInvalidatorBridge(
-            &mock_profile_, sync_thread_.message_loop_proxy()));
-  }
-
-  virtual void TearDown() OVERRIDE {
-    bridge_->StopForShutdown();
-    sync_thread_.Stop();
-    // Must be reset only after the sync thread is stopped.
-    bridge_.reset();
-    EXPECT_EQ(NULL, sync_handler_.get());
-    if (!sync_handler_notification_success_)
-      ADD_FAILURE() << "Sync handler did not receive proper notification.";
-  }
-
-  void VerifyAndDestroyObserver(
-      const syncer::ModelTypeInvalidationMap& expected_invalidations) {
-    ASSERT_TRUE(sync_thread_.message_loop_proxy()->PostTask(
-        FROM_HERE,
-        base::Bind(&AndroidInvalidatorBridgeTest::
-                       VerifyAndDestroyObserverOnSyncThread,
-                   base::Unretained(this),
-                   expected_invalidations)));
-    BlockForSyncThread();
-  }
-
-  void CreateObserver() {
-    ASSERT_TRUE(sync_thread_.message_loop_proxy()->PostTask(
-        FROM_HERE,
-        base::Bind(
-            &AndroidInvalidatorBridgeTest::CreateObserverOnSyncThread,
-            base::Unretained(this))));
-    BlockForSyncThread();
-  }
-
-  void UpdateEnabledTypes(syncer::ModelTypeSet enabled_types) {
-    ASSERT_TRUE(sync_thread_.message_loop_proxy()->PostTask(
-        FROM_HERE,
-        base::Bind(
-            &AndroidInvalidatorBridgeTest::
-                UpdateEnabledTypesOnSyncThread,
-            base::Unretained(this),
-            enabled_types)));
-    BlockForSyncThread();
-  }
-
-  void TriggerRefreshNotification(
-      const syncer::ModelTypeInvalidationMap& invalidation_map) {
-    content::NotificationService::current()->Notify(
-        chrome::NOTIFICATION_SYNC_REFRESH_REMOTE,
-        content::Source<Profile>(&mock_profile_),
-        content::Details<const syncer::ObjectIdInvalidationMap>(
-            ModelTypeInvalidationMapToObjectIdInvalidationMap(
-                &invalidation_map));
-    BlockForSyncThread();
-  }
-
- private:
-  void VerifyAndDestroyObserverOnSyncThread(
-      const syncer::ModelTypeInvalidationMap& expected_invalidations) {
-    DCHECK(sync_thread_.message_loop_proxy()->RunsTasksOnCurrentThread());
-    if (sync_handler_) {
-      sync_handler_notification_success_ =
-          (sync_handler_->GetInvalidationCount() == 1) &&
-          ObjectIdInvalidationMapEquals(
-              sync_handler_->GetLastInvalidationMap(),
-              syncer::ModelTypeInvalidationMapToObjectIdInvalidationMap(
-                  expected_invalidations));
-      bridge_->UnregisterHandler(sync_handler_.get());
-    } else {
-      sync_handler_notification_success_ = false;
-    }
-    sync_handler_.reset();
-  }
-
-  void CreateObserverOnSyncThread() {
-    DCHECK(sync_thread_.message_loop_proxy()->RunsTasksOnCurrentThread());
-    sync_handler_.reset(new syncer::FakeInvalidationHandler());
-    bridge_->RegisterHandler(sync_handler_.get());
-  }
-
-  void UpdateEnabledTypesOnSyncThread(
-      syncer::ModelTypeSet enabled_types) {
-    DCHECK(sync_thread_.message_loop_proxy()->RunsTasksOnCurrentThread());
-    bridge_->UpdateRegisteredIds(
-        sync_handler_.get(), ModelTypeSetToObjectIdSet(enabled_types));
-  }
-
-  void BlockForSyncThread() {
-    // Post a task to the sync thread's message loop and block until
-    // it runs.
-    base::RunLoop run_loop;
-    ASSERT_TRUE(sync_thread_.message_loop_proxy()->PostTaskAndReply(
-        FROM_HERE,
-        base::Bind(&base::DoNothing),
-        run_loop.QuitClosure()));
-    run_loop.Run();
-  }
-
-  base::MessageLoop ui_loop_;
-  content::TestBrowserThread ui_thread_;
-  base::Thread sync_thread_;
-  NiceMock<ProfileMock> mock_profile_;
-  // Created/used/destroyed on sync thread.
-  scoped_ptr<syncer::FakeInvalidationHandler> sync_handler_;
-  bool sync_handler_notification_success_;
-  scoped_ptr<AndroidInvalidatorBridge> bridge_;
-};
-
-// Adds an observer on the sync thread, triggers a remote refresh
-// invalidation, and ensures the bridge posts a REMOTE_INVALIDATION
-// with the proper state to it.
-TEST_F(AndroidInvalidatorBridgeTest, RemoteNotification) {
-  const syncer::ModelTypeSet types(syncer::SESSIONS);
-  const syncer::ModelTypeInvalidationMap& invalidation_map =
-      ModelTypeSetToInvalidationMap(types, std::string());
-  CreateObserver();
-  UpdateEnabledTypes(syncer::ModelTypeSet(syncer::SESSIONS));
-  TriggerRefreshNotification(invalidation_map);
-  VerifyAndDestroyObserver(invalidation_map);
-}
-
-// Adds an observer on the sync thread, triggers a remote refresh
-// notification with empty state map and ensures the bridge posts a
-// REMOTE_INVALIDATION with the proper state to it.
-TEST_F(AndroidInvalidatorBridgeTest, RemoteNotificationEmptyPayloadMap) {
-  const syncer::ModelTypeSet enabled_types(
-      syncer::BOOKMARKS, syncer::TYPED_URLS);
-  const syncer::ModelTypeInvalidationMap enabled_types_invalidation_map =
-      syncer::ModelTypeSetToInvalidationMap(enabled_types, std::string());
-  CreateObserver();
-  UpdateEnabledTypes(enabled_types);
-  TriggerRefreshNotification(syncer::ModelTypeInvalidationMap());
-  VerifyAndDestroyObserver(enabled_types_invalidation_map);
-}
-
-}  // namespace
-}  // namespace browser_sync
diff --git a/chrome/browser/sync/glue/data_type_manager_impl.cc b/chrome/browser/sync/glue/data_type_manager_impl.cc
index 63611d6..c5cbc8e 100644
--- a/chrome/browser/sync/glue/data_type_manager_impl.cc
+++ b/chrome/browser/sync/glue/data_type_manager_impl.cc
@@ -77,10 +77,7 @@
 
 void DataTypeManagerImpl::Configure(syncer::ModelTypeSet desired_types,
                                     syncer::ConfigureReason reason) {
-  desired_types.PutAll(syncer::ControlTypes());
-  // The list of managed users created by this profile is always synced,
-  // but they are not a control type.
-  desired_types.Put(syncer::MANAGED_USERS);
+  desired_types.PutAll(syncer::CoreTypes());
   ConfigureImpl(desired_types, reason);
 }
 
@@ -242,7 +239,7 @@
 
 syncer::ModelTypeSet DataTypeManagerImpl::GetPriorityTypes() const {
   syncer::ModelTypeSet high_priority_types;
-  high_priority_types.PutAll(syncer::ControlTypes());
+  high_priority_types.PutAll(syncer::PriorityCoreTypes());
   high_priority_types.PutAll(syncer::PriorityUserTypes());
   return high_priority_types;
 }
@@ -447,9 +444,8 @@
   }
 
   DCHECK(result.status == PARTIAL_SUCCESS || result.status == OK);
-  DCHECK(!result.status == OK ||
-         (result.needs_crypto.Empty() &&
-          result.failed_data_types.empty()));
+  DCHECK(result.status != OK ||
+         (result.needs_crypto.Empty() && result.failed_data_types.empty()));
 
   // It's possible this is a retry to disable failed types, in which case
   // the association would be SUCCESS, but the overall configuration should
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 254ba72..48eeef5 100644
--- a/chrome/browser/sync/glue/data_type_manager_impl_unittest.cc
+++ b/chrome/browser/sync/glue/data_type_manager_impl_unittest.cc
@@ -41,15 +41,23 @@
   return result.status;
 }
 
-syncer::ModelTypeSet PriorityTypes() {
-  syncer::ModelTypeSet result = syncer::ControlTypes();
-  result.Put(syncer::MANAGED_USERS);
+// Those types that are priority AND always configured.
+syncer::ModelTypeSet HighPriorityTypes() {
+  syncer::ModelTypeSet result = syncer::PriorityCoreTypes();
   return result;
 }
 
-// Helper for unioning with control types.
-syncer::ModelTypeSet AddPriorityTypesTo(syncer::ModelTypeSet types) {
-  syncer::ModelTypeSet result = PriorityTypes();
+// Helper for unioning with priority types.
+syncer::ModelTypeSet AddHighPriorityTypesTo(syncer::ModelTypeSet types) {
+  syncer::ModelTypeSet result = HighPriorityTypes();
+  result.PutAll(types);
+  return result;
+}
+
+// Helper for unioning with core types.
+syncer::ModelTypeSet AddLowPriorityCoreTypesTo(syncer::ModelTypeSet types) {
+  syncer::ModelTypeSet result = syncer::Difference(syncer::CoreTypes(),
+                                                   syncer::PriorityCoreTypes());
   result.PutAll(types);
   return result;
 }
@@ -155,7 +163,7 @@
                             configurer,
                             observer,
                             failed_data_types_handler),
-        custom_priority_types_(PriorityTypes()) {}
+        custom_priority_types_(HighPriorityTypes()) {}
 
   void set_priority_types(const syncer::ModelTypeSet& priority_types) {
     custom_priority_types_ = priority_types;
@@ -262,6 +270,7 @@
   EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
 
   FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
+  FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
   EXPECT_EQ(DataTypeManager::CONFIGURED, dtm_->state());
 
   dtm_->Stop();
@@ -272,7 +281,6 @@
 // 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);
@@ -280,6 +288,7 @@
   Configure(dtm_.get(), ModelTypeSet(BOOKMARKS));
   EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
 
+  FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
   FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS), ModelTypeSet());
   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
 
@@ -295,8 +304,6 @@
 TEST_F(SyncDataTypeManagerImplTest, ConfigureSlowLoadingType) {
   AddController(BOOKMARKS);
   AddController(APPS);
-  dtm_->set_priority_types(
-      AddPriorityTypesTo(syncer::ModelTypeSet(BOOKMARKS, APPS)));
 
   GetController(BOOKMARKS)->SetDelayModelLoad();
 
@@ -310,6 +317,7 @@
   Configure(dtm_.get(), types);
   EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
 
+  FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
   FinishDownload(*dtm_, types, ModelTypeSet());
   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
 
@@ -327,6 +335,7 @@
   GetController(BOOKMARKS)->SimulateModelLoadFinishing();
 
   FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
+  FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
   GetController(BOOKMARKS)->SimulateModelLoadFinishing();
 
   GetController(BOOKMARKS)->FinishStart(DataTypeController::OK);
@@ -342,7 +351,6 @@
 // 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();
@@ -364,7 +372,6 @@
 // controller even after the DTM is stopped and destroyed.
 TEST_F(SyncDataTypeManagerImplTest, ConfigureOneStopWhileStartingModel) {
   AddController(BOOKMARKS);
-  dtm_->set_priority_types(AddPriorityTypesTo(syncer::ModelTypeSet(BOOKMARKS)));
 
   {
     SetConfigureStartExpectation();
@@ -373,6 +380,7 @@
     Configure(dtm_.get(), ModelTypeSet(BOOKMARKS));
     EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
 
+    FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
     FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS), ModelTypeSet());
     EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
 
@@ -391,7 +399,6 @@
 // destroyed.
 TEST_F(SyncDataTypeManagerImplTest, ConfigureOneStopWhileAssociating) {
   AddController(BOOKMARKS);
-  dtm_->set_priority_types(AddPriorityTypesTo(syncer::ModelTypeSet(BOOKMARKS)));
 
   {
     SetConfigureStartExpectation();
@@ -400,6 +407,7 @@
     Configure(dtm_.get(), ModelTypeSet(BOOKMARKS));
     EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
 
+    FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
     FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS), ModelTypeSet());
     EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
 
@@ -420,7 +428,6 @@
 //   5) Stop the DTM.
 TEST_F(SyncDataTypeManagerImplTest, OneWaitingForCrypto) {
   AddController(PASSWORDS);
-  dtm_->set_priority_types(AddPriorityTypesTo(syncer::ModelTypeSet(PASSWORDS)));
 
   SetConfigureStartExpectation();
   SetConfigureDoneExpectation(DataTypeManager::PARTIAL_SUCCESS);
@@ -432,6 +439,7 @@
   EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
 
   // Step 2.
+  FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
   FinishDownload(*dtm_, types, ModelTypeSet());
   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
 
@@ -442,6 +450,7 @@
 
   // Step 4.
   FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
+  FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
   EXPECT_EQ(DataTypeManager::CONFIGURED, dtm_->state());
 
   // Step 5.
@@ -461,8 +470,6 @@
 TEST_F(SyncDataTypeManagerImplTest, ConfigureOneThenBoth) {
   AddController(BOOKMARKS);
   AddController(PREFERENCES);
-  dtm_->set_priority_types(
-      AddPriorityTypesTo(syncer::ModelTypeSet(BOOKMARKS, PREFERENCES)));
 
   SetConfigureStartExpectation();
   SetConfigureDoneExpectation(DataTypeManager::OK);
@@ -472,6 +479,7 @@
   EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
 
   // Step 2.
+  FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
   FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS), ModelTypeSet());
   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
 
@@ -488,6 +496,7 @@
   EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
 
   // Step 5.
+  FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
   FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS, PREFERENCES), ModelTypeSet());
   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
 
@@ -512,8 +521,6 @@
 TEST_F(SyncDataTypeManagerImplTest, ConfigureOneThenSwitch) {
   AddController(BOOKMARKS);
   AddController(PREFERENCES);
-  dtm_->set_priority_types(
-      AddPriorityTypesTo(syncer::ModelTypeSet(BOOKMARKS, PREFERENCES)));
 
   SetConfigureStartExpectation();
   SetConfigureDoneExpectation(DataTypeManager::OK);
@@ -523,6 +530,7 @@
   EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
 
   // Step 2.
+  FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
   FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS), ModelTypeSet());
   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
 
@@ -539,6 +547,7 @@
   EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
 
   // Step 5.
+  FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
   FinishDownload(*dtm_, ModelTypeSet(PREFERENCES), ModelTypeSet());
   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
 
@@ -563,8 +572,6 @@
 TEST_F(SyncDataTypeManagerImplTest, ConfigureWhileOneInFlight) {
   AddController(BOOKMARKS);
   AddController(PREFERENCES);
-  dtm_->set_priority_types(
-      AddPriorityTypesTo(syncer::ModelTypeSet(BOOKMARKS, PREFERENCES)));
 
   SetConfigureStartExpectation();
   SetConfigureDoneExpectation(DataTypeManager::OK);
@@ -574,6 +581,7 @@
   EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
 
   // Step 2.
+  FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
   FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS), ModelTypeSet());
   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
 
@@ -586,6 +594,7 @@
   EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
 
   // Step 5.
+  FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
   FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS, PREFERENCES), ModelTypeSet());
   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
 
@@ -603,7 +612,6 @@
 // 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);
@@ -611,6 +619,7 @@
   Configure(dtm_.get(), ModelTypeSet(BOOKMARKS));
   EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
 
+  FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
   FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS), ModelTypeSet());
   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
 
@@ -630,8 +639,6 @@
 TEST_F(SyncDataTypeManagerImplTest, SecondControllerFails) {
   AddController(BOOKMARKS);
   AddController(PREFERENCES);
-  dtm_->set_priority_types(
-      AddPriorityTypesTo(syncer::ModelTypeSet(BOOKMARKS, PREFERENCES)));
 
   SetConfigureStartExpectation();
   SetConfigureDoneExpectation(DataTypeManager::UNRECOVERABLE_ERROR);
@@ -641,6 +648,7 @@
   EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
 
   // Step 2.
+  FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
   FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS, PREFERENCES), ModelTypeSet());
   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
 
@@ -670,8 +678,6 @@
 TEST_F(SyncDataTypeManagerImplTest, OneControllerFailsAssociation) {
   AddController(BOOKMARKS);
   AddController(PREFERENCES);
-  dtm_->set_priority_types(
-      AddPriorityTypesTo(syncer::ModelTypeSet(BOOKMARKS, PREFERENCES)));
 
   SetConfigureStartExpectation();
   SetConfigureDoneExpectation(DataTypeManager::PARTIAL_SUCCESS);
@@ -681,6 +687,7 @@
   EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
 
   // Step 2.
+  FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
   FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS, PREFERENCES), ModelTypeSet());
   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
 
@@ -694,6 +701,7 @@
   EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
 
   // Step 5.
+  FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
   FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS), ModelTypeSet());
   EXPECT_EQ(DataTypeManager::CONFIGURED, dtm_->state());
 
@@ -713,8 +721,6 @@
 TEST_F(SyncDataTypeManagerImplTest, ConfigureWhileDownloadPending) {
   AddController(BOOKMARKS);
   AddController(PREFERENCES);
-  dtm_->set_priority_types(
-      AddPriorityTypesTo(syncer::ModelTypeSet(BOOKMARKS, PREFERENCES)));
 
   SetConfigureStartExpectation();
   SetConfigureDoneExpectation(DataTypeManager::OK);
@@ -728,10 +734,11 @@
   EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
 
   // Step 3.
-  FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS), ModelTypeSet());
+  FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
   EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
 
   // Step 4.
+  FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
   FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS, PREFERENCES), ModelTypeSet());
   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
 
@@ -760,23 +767,23 @@
 TEST_F(SyncDataTypeManagerImplTest, ConfigureWhileDownloadPendingWithFailure) {
   AddController(BOOKMARKS);
   AddController(PREFERENCES);
-  dtm_->set_priority_types(
-      AddPriorityTypesTo(syncer::ModelTypeSet(BOOKMARKS, PREFERENCES)));
 
   SetConfigureStartExpectation();
   SetConfigureDoneExpectation(DataTypeManager::OK);
 
   // Step 1.
   Configure(dtm_.get(), ModelTypeSet(BOOKMARKS));
-  EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
+  FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
+  EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
 
   // Step 2.
   Configure(dtm_.get(), ModelTypeSet(BOOKMARKS, PREFERENCES));
-  EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
+  EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
 
   // Step 3.
-  FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS), ModelTypeSet(BOOKMARKS));
-  EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
+  FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
+  FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS), ModelTypeSet());
+  EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
 
   // Step 4.
   FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS, PREFERENCES), ModelTypeSet());
@@ -797,13 +804,13 @@
 // 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);
 
   // Initial setup.
   Configure(dtm_.get(), ModelTypeSet(BOOKMARKS));
+  FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
   FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS), ModelTypeSet());
   GetController(BOOKMARKS)->FinishStart(DataTypeController::OK);
 
@@ -824,6 +831,7 @@
 
   // The DTM will call ConfigureDataTypes(), even though it is unnecessary.
   FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
+  FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
   EXPECT_EQ(DataTypeManager::CONFIGURED, dtm_->state());
   Mock::VerifyAndClearExpectations(&observer_);
 
@@ -831,6 +839,7 @@
   SetConfigureStartExpectation();
   SetConfigureDoneExpectation(DataTypeManager::OK);
   Configure(dtm_.get(), to_migrate);
+  FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
   FinishDownload(*dtm_, to_migrate, ModelTypeSet());
   GetController(BOOKMARKS)->FinishStart(DataTypeController::OK);
   EXPECT_EQ(DataTypeManager::CONFIGURED, dtm_->state());
@@ -840,13 +849,12 @@
 TEST_F(SyncDataTypeManagerImplTest, ConfigureDuringPurge) {
   AddController(BOOKMARKS);
   AddController(PREFERENCES);
-  dtm_->set_priority_types(
-      AddPriorityTypesTo(syncer::ModelTypeSet(BOOKMARKS, PREFERENCES)));
 
   // Initial configure.
   SetConfigureStartExpectation();
   SetConfigureDoneExpectation(DataTypeManager::OK);
   Configure(dtm_.get(), ModelTypeSet(BOOKMARKS));
+  FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
   FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS), ModelTypeSet());
   GetController(BOOKMARKS)->FinishStart(DataTypeController::OK);
   EXPECT_EQ(DataTypeManager::CONFIGURED, dtm_->state());
@@ -876,6 +884,7 @@
   EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
 
   // Now invoke the callback for the second configure request.
+  FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
   FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS, PREFERENCES), ModelTypeSet());
   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
 
@@ -889,11 +898,9 @@
 TEST_F(SyncDataTypeManagerImplTest, PrioritizedConfiguration) {
   AddController(BOOKMARKS);
   AddController(PREFERENCES);
-  dtm_->set_priority_types(
-      AddPriorityTypesTo(syncer::ModelTypeSet(BOOKMARKS, PREFERENCES)));
 
   dtm_->set_priority_types(
-      AddPriorityTypesTo(syncer::ModelTypeSet(PREFERENCES)));
+      AddHighPriorityTypesTo(syncer::ModelTypeSet(PREFERENCES)));
 
   // Initial configure.
   SetConfigureStartExpectation();
@@ -901,12 +908,13 @@
 
   // Initially only PREFERENCES is configured.
   configurer_.set_expected_configure_types(
-      AddPriorityTypesTo(ModelTypeSet(PREFERENCES)));
+      AddHighPriorityTypesTo(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));
+  configurer_.set_expected_configure_types(
+      AddLowPriorityCoreTypesTo(ModelTypeSet(BOOKMARKS)));
   FinishDownload(*dtm_, ModelTypeSet(PREFERENCES), ModelTypeSet());
   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
 
@@ -924,7 +932,7 @@
   AddController(APPS);
 
   dtm_->set_priority_types(
-      AddPriorityTypesTo(syncer::ModelTypeSet(PREFERENCES)));
+      AddHighPriorityTypesTo(syncer::ModelTypeSet(PREFERENCES)));
 
   // Initial configure.
   SetConfigureStartExpectation();
@@ -932,11 +940,12 @@
 
   // Reconfigure while associating PREFERENCES and downloading BOOKMARKS.
   configurer_.set_expected_configure_types(
-      AddPriorityTypesTo(ModelTypeSet(PREFERENCES)));
+      AddHighPriorityTypesTo(ModelTypeSet(PREFERENCES)));
   Configure(dtm_.get(), ModelTypeSet(BOOKMARKS, PREFERENCES));
   EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
 
-  configurer_.set_expected_configure_types(ModelTypeSet(BOOKMARKS));
+  configurer_.set_expected_configure_types(
+      AddLowPriorityCoreTypesTo(ModelTypeSet(BOOKMARKS)));
   FinishDownload(*dtm_, ModelTypeSet(PREFERENCES), ModelTypeSet());
   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
 
@@ -947,12 +956,13 @@
   // Reconfiguration starts after downloading and association of previous
   // types finish.
   configurer_.set_expected_configure_types(
-      AddPriorityTypesTo(ModelTypeSet(PREFERENCES)));
+      AddHighPriorityTypesTo(ModelTypeSet(PREFERENCES)));
   FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS), ModelTypeSet());
   GetController(PREFERENCES)->FinishStart(DataTypeController::OK);
   EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
 
-  configurer_.set_expected_configure_types(ModelTypeSet(BOOKMARKS, APPS));
+  configurer_.set_expected_configure_types(
+      AddLowPriorityCoreTypesTo(ModelTypeSet(BOOKMARKS, APPS)));
   FinishDownload(*dtm_, ModelTypeSet(PREFERENCES), ModelTypeSet());
   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
 
@@ -971,7 +981,7 @@
   AddController(PREFERENCES);
 
   dtm_->set_priority_types(
-      AddPriorityTypesTo(syncer::ModelTypeSet(PREFERENCES)));
+      AddHighPriorityTypesTo(syncer::ModelTypeSet(PREFERENCES)));
 
   // Initial configure.
   SetConfigureStartExpectation();
@@ -979,12 +989,13 @@
 
   // Initially only PREFERENCES is configured.
   configurer_.set_expected_configure_types(
-      AddPriorityTypesTo(ModelTypeSet(PREFERENCES)));
+      AddHighPriorityTypesTo(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));
+  configurer_.set_expected_configure_types(
+      AddLowPriorityCoreTypesTo(ModelTypeSet(BOOKMARKS)));
   FinishDownload(*dtm_, ModelTypeSet(PREFERENCES), ModelTypeSet());
   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
 
@@ -1005,7 +1016,7 @@
   AddController(PREFERENCES);
 
   dtm_->set_priority_types(
-      AddPriorityTypesTo(syncer::ModelTypeSet(PREFERENCES)));
+      AddHighPriorityTypesTo(syncer::ModelTypeSet(PREFERENCES)));
 
   // Initial configure.
   SetConfigureStartExpectation();
@@ -1013,12 +1024,13 @@
 
   // Initially only PREFERENCES is configured.
   configurer_.set_expected_configure_types(
-      AddPriorityTypesTo(ModelTypeSet(PREFERENCES)));
+      AddHighPriorityTypesTo(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));
+  configurer_.set_expected_configure_types(
+      AddLowPriorityCoreTypesTo(ModelTypeSet(BOOKMARKS)));
   FinishDownload(*dtm_, ModelTypeSet(PREFERENCES), ModelTypeSet());
   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
 
@@ -1040,7 +1052,7 @@
   AddController(BOOKMARKS);     // Will succeed.
 
   dtm_->set_priority_types(
-      AddPriorityTypesTo(syncer::ModelTypeSet(PREFERENCES)));
+      AddHighPriorityTypesTo(syncer::ModelTypeSet(PREFERENCES)));
 
   // Initial configure.
   SetConfigureStartExpectation();
@@ -1048,12 +1060,13 @@
 
   // Initially only PREFERENCES is configured.
   configurer_.set_expected_configure_types(
-      AddPriorityTypesTo(ModelTypeSet(PREFERENCES)));
+      AddHighPriorityTypesTo(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));
+  configurer_.set_expected_configure_types(
+      AddLowPriorityCoreTypesTo(ModelTypeSet(BOOKMARKS)));
   FinishDownload(*dtm_, ModelTypeSet(PREFERENCES), ModelTypeSet());
   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
 
@@ -1069,9 +1082,10 @@
 
   // Reconfigure without PREFERENCES after the BOOKMARKS download completes,
   // then reconfigure with BOOKMARKS.
-  configurer_.set_expected_configure_types(PriorityTypes());
+  configurer_.set_expected_configure_types(HighPriorityTypes());
   FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS), ModelTypeSet());
-  configurer_.set_expected_configure_types(ModelTypeSet(BOOKMARKS));
+  configurer_.set_expected_configure_types(
+      AddLowPriorityCoreTypesTo(ModelTypeSet(BOOKMARKS)));
   FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
 
   // Reconfigure with BOOKMARKS.
@@ -1091,7 +1105,7 @@
   AddController(BOOKMARKS);    // Will fail.
 
   dtm_->set_priority_types(
-      AddPriorityTypesTo(syncer::ModelTypeSet(PREFERENCES)));
+      AddHighPriorityTypesTo(syncer::ModelTypeSet(PREFERENCES)));
 
   // Initial configure.
   SetConfigureStartExpectation();
@@ -1099,12 +1113,13 @@
 
   // Initially only PREFERENCES is configured.
   configurer_.set_expected_configure_types(
-      AddPriorityTypesTo(ModelTypeSet(PREFERENCES)));
+      AddHighPriorityTypesTo(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));
+  configurer_.set_expected_configure_types(
+      AddLowPriorityCoreTypesTo(ModelTypeSet(BOOKMARKS)));
   FinishDownload(*dtm_, ModelTypeSet(PREFERENCES), ModelTypeSet());
   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
 
@@ -1121,15 +1136,17 @@
   // Make BOOKMARKS association fail, which triggers reconfigure with only
   // PREFERENCES.
   configurer_.set_expected_configure_types(
-      AddPriorityTypesTo(ModelTypeSet(PREFERENCES)));
-  GetController(BOOKMARKS)->FinishStart(
-      DataTypeController::ASSOCIATION_FAILED);
+      AddHighPriorityTypesTo(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.
+  configurer_.set_expected_configure_types(
+      AddLowPriorityCoreTypesTo(ModelTypeSet()));
   FinishDownload(*dtm_, ModelTypeSet(PREFERENCES), ModelTypeSet());
+  FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
   EXPECT_EQ(DataTypeManager::CONFIGURED, dtm_->state());
   EXPECT_EQ(DataTypeController::RUNNING, GetController(PREFERENCES)->state());
   EXPECT_EQ(DataTypeController::NOT_RUNNING,
diff --git a/chrome/browser/sync/glue/device_info.cc b/chrome/browser/sync/glue/device_info.cc
index e593d00..c21a74b 100644
--- a/chrome/browser/sync/glue/device_info.cc
+++ b/chrome/browser/sync/glue/device_info.cc
@@ -6,6 +6,7 @@
 
 #include "base/command_line.h"
 #include "base/threading/sequenced_worker_pool.h"
+#include "base/values.h"
 #include "chrome/common/chrome_version_info.h"
 #include "chrome/common/chrome_switches.h"
 #include "content/public/browser/browser_thread.h"
@@ -40,6 +41,28 @@
   };
 }
 
+std::string DeviceTypeToString(sync_pb::SyncEnums::DeviceType device_type) {
+  switch (device_type) {
+    case sync_pb::SyncEnums_DeviceType_TYPE_WIN:
+      return "WIN";
+    case sync_pb::SyncEnums_DeviceType_TYPE_MAC:
+      return "MAC";
+    case sync_pb::SyncEnums_DeviceType_TYPE_LINUX:
+      return "LINUX";
+    case sync_pb::SyncEnums_DeviceType_TYPE_CROS:
+      return "CHROME OS";
+    case sync_pb::SyncEnums_DeviceType_TYPE_OTHER:
+      return "OTHER";
+    case sync_pb::SyncEnums_DeviceType_TYPE_PHONE:
+      return "PHONE";
+    case sync_pb::SyncEnums_DeviceType_TYPE_TABLET:
+      return "TABLET";
+    default:
+      NOTREACHED();
+      return "UNKNOWN";
+  }
+}
+
 }  // namespace
 
 DeviceInfo::DeviceInfo(const std::string& guid,
@@ -143,6 +166,20 @@
   return user_agent;
 }
 
+base::DictionaryValue* DeviceInfo::ToValue() {
+  base::DictionaryValue* value = new base::DictionaryValue();
+  value->SetString("Id", public_id_);
+  value->SetString("Client Name", client_name_);
+  value->SetString("Chrome Version", chrome_version_);
+  value->SetString("Sync User Agent", sync_user_agent_);
+  value->SetString("Device Type", DeviceTypeToString(device_type_));
+  return value;
+}
+
+void DeviceInfo::SetPublicId(std::string id) {
+  public_id_ = id;
+}
+
 // static.
 void DeviceInfo::CreateLocalDeviceInfo(
     const std::string& guid,
diff --git a/chrome/browser/sync/glue/device_info.h b/chrome/browser/sync/glue/device_info.h
index 4711925..f8645a0 100644
--- a/chrome/browser/sync/glue/device_info.h
+++ b/chrome/browser/sync/glue/device_info.h
@@ -11,6 +11,10 @@
 #include "base/bind.h"
 #include "sync/protocol/sync.pb.h"
 
+namespace base {
+class DictionaryValue;
+}
+
 namespace chrome {
 class VersionInfo;
 }
@@ -50,6 +54,16 @@
   // Compares this object's fields with another's.
   bool Equals(const DeviceInfo& other) const;
 
+  // Apps can set ids for a device that is meaningful to them but
+  // not unique enough so the user can be tracked. Exposing |guid|
+  // would lead to a stable unique id for a device which can potentially
+  // be used for tracking.
+  void SetPublicId(std::string id);
+
+  // Converts the |DeviceInfo| values to a JS friendly DictionaryValue,
+  // which extension APIs can expose to third party apps.
+  base::DictionaryValue* ToValue();
+
   static sync_pb::SyncEnums::DeviceType GetLocalDeviceType();
 
   // Creates a |DeviceInfo| object representing the local device and passes
@@ -88,6 +102,8 @@
 
   const sync_pb::SyncEnums::DeviceType device_type_;
 
+  std::string public_id_;
+
   DISALLOW_COPY_AND_ASSIGN(DeviceInfo);
 };
 
diff --git a/chrome/browser/sync/glue/session_change_processor.cc b/chrome/browser/sync/glue/session_change_processor.cc
index 24b90c9..ff73af1 100644
--- a/chrome/browser/sync/glue/session_change_processor.cc
+++ b/chrome/browser/sync/glue/session_change_processor.cc
@@ -277,8 +277,13 @@
         LOG(WARNING) << "Local session data deleted. Ignoring until next local "
                      << "navigation event.";
       } else {
-        session_model_associator_->DisassociateForeignSession(
-            specifics.session_tag());
+        if (specifics.has_header()) {
+          // Disassociate only when header node is deleted. For tab node
+          // deletions, the header node will be updated and foreign tab will
+          // get deleted.
+          session_model_associator_->DisassociateForeignSession(
+              specifics.session_tag());
+        }
       }
       continue;
     }
diff --git a/chrome/browser/sync/glue/session_model_associator.cc b/chrome/browser/sync/glue/session_model_associator.cc
index ec7e281..d66a96c 100644
--- a/chrome/browser/sync/glue/session_model_associator.cc
+++ b/chrome/browser/sync/glue/session_model_associator.cc
@@ -176,7 +176,6 @@
   synced_session_tracker_.ResetSessionTracking(local_tag);
   std::set<SyncedWindowDelegate*> windows =
       SyncedWindowDelegate::GetSyncedWindowDelegates();
-  std::set<int64> used_sync_ids;
   for (std::set<SyncedWindowDelegate*>::const_iterator i =
            windows.begin(); i != windows.end(); ++i) {
     // Make sure the window has tabs and a viewable window. The viewable window
@@ -223,7 +222,6 @@
               tab_id > TabNodePool::kInvalidTabID) {
             UpdateTabIdIfNecessary(synced_tab->GetSyncId(), tab_id);
             found_tabs = true;
-            used_sync_ids.insert(synced_tab->GetSyncId());
             window_s.add_tab(tab_id);
           }
           continue;
@@ -269,14 +267,8 @@
     }
   }
 
-  // Sync nodes tracked by tab_map_ are used.
-  for (TabLinksMap::const_iterator tab_iter = tab_map_.begin();
-       tab_iter != tab_map_.end(); ++tab_iter) {
-    used_sync_ids.insert(tab_iter->second->sync_id());
-  }
-
   // Free old sync nodes.
-  tab_pool_.FreeUnusedTabNodes(used_sync_ids);
+  tab_pool_.FreeUnassociatedTabNodes();
   // Free memory for closed windows and tabs.
   synced_session_tracker_.CleanupSession(local_tag);
 
@@ -345,7 +337,7 @@
   if (tab_map_iter == tab_map_.end()) {
     sync_id = tab->GetSyncId();
     // if there is an old sync node for the tab, reuse it.
-    if (!tab_pool_.ReassociateTabNode(sync_id, tab_id)) {
+    if (!tab_pool_.IsUnassociatedTabNode(sync_id)) {
       // This is a new tab, get a sync node for it.
       sync_id = tab_pool_.GetFreeTabNode();
       if (sync_id == syncer::kInvalidId) {
@@ -357,9 +349,9 @@
         }
         return false;
       }
-      tab_pool_.AssociateTabNode(sync_id, tab_id);
       tab->SetSyncId(sync_id);
     }
+    tab_pool_.AssociateTabNode(sync_id, tab_id);
     tab_link = new TabLink(sync_id, tab);
     tab_map_[tab_id] = make_linked_ptr<TabLink>(tab_link);
   } else {
diff --git a/chrome/browser/sync/glue/session_model_associator.h b/chrome/browser/sync/glue/session_model_associator.h
index 6aaa00b..9870053 100644
--- a/chrome/browser/sync/glue/session_model_associator.h
+++ b/chrome/browser/sync/glue/session_model_associator.h
@@ -217,6 +217,8 @@
   FRIEND_TEST_ALL_PREFIXES(ProfileSyncServiceSessionTest, ValidTabs);
   FRIEND_TEST_ALL_PREFIXES(ProfileSyncServiceSessionTest, ExistingTabs);
   FRIEND_TEST_ALL_PREFIXES(ProfileSyncServiceSessionTest, MissingLocalTabNode);
+  FRIEND_TEST_ALL_PREFIXES(ProfileSyncServiceSessionTest,
+                           TabPoolFreeNodeLimits);
   FRIEND_TEST_ALL_PREFIXES(SyncSessionModelAssociatorTest,
                            PopulateSessionHeader);
   FRIEND_TEST_ALL_PREFIXES(SyncSessionModelAssociatorTest,
diff --git a/chrome/browser/sync/glue/sync_backend_host.cc b/chrome/browser/sync/glue/sync_backend_host.cc
index 294742e..3ab713f 100644
--- a/chrome/browser/sync/glue/sync_backend_host.cc
+++ b/chrome/browser/sync/glue/sync_backend_host.cc
@@ -383,6 +383,10 @@
     factory_switches.backoff_override =
         InternalComponentsFactoryImpl::BACKOFF_SHORT_INITIAL_RETRY_OVERRIDE;
   }
+  if (cl->HasSwitch(switches::kSyncEnableGetUpdateAvoidance)) {
+    factory_switches.pre_commit_updates_policy =
+        InternalComponentsFactoryImpl::FORCE_ENABLE_PRE_COMMIT_UPDATE_AVOIDANCE;
+  }
 
   initialization_state_ = CREATING_SYNC_MANAGER;
   InitCore(DoInitializeOptions(
@@ -561,9 +565,7 @@
 
   if (invalidation_handler_registered_) {
     if (sync_disabled) {
-      invalidator_->UpdateRegisteredInvalidationIds(
-          this,
-          syncer::ObjectIdSet());
+      UnregisterInvalidationIds();
     }
     invalidator_->UnregisterInvalidationHandler(this);
     invalidator_ = NULL;
@@ -603,6 +605,14 @@
   core_ = NULL;  // Releases reference to core_.
 }
 
+void SyncBackendHost::UnregisterInvalidationIds() {
+  if (invalidation_handler_registered_) {
+    invalidator_->UpdateRegisteredInvalidationIds(
+        this,
+        syncer::ObjectIdSet());
+  }
+}
+
 void SyncBackendHost::ConfigureDataTypes(
     syncer::ConfigureReason reason,
     const DataTypeConfigStateMap& config_state_map,
diff --git a/chrome/browser/sync/glue/sync_backend_host.h b/chrome/browser/sync/glue/sync_backend_host.h
index 9498ece..a539ec6 100644
--- a/chrome/browser/sync/glue/sync_backend_host.h
+++ b/chrome/browser/sync/glue/sync_backend_host.h
@@ -228,6 +228,10 @@
   // Must be called *after* StopSyncingForShutdown.
   void Shutdown(bool sync_disabled);
 
+  // Removes all current registrations from the backend on the
+  // InvalidationService.
+  void UnregisterInvalidationIds();
+
   // Changes the set of data types that are currently being synced.
   // The ready_task will be run when configuration is done with the
   // set of all types that failed configuration (i.e., if its argument
diff --git a/chrome/browser/sync/glue/tab_node_pool.cc b/chrome/browser/sync/glue/tab_node_pool.cc
index 5d44c39..2b41851 100644
--- a/chrome/browser/sync/glue/tab_node_pool.cc
+++ b/chrome/browser/sync/glue/tab_node_pool.cc
@@ -20,7 +20,8 @@
     "Server did not create the top-level sessions node. We "
     "might be running against an out-of-date server.";
 
-static const size_t kMaxNumberOfFreeNodes = 25;
+const size_t TabNodePool::kFreeNodesLowWatermark = 25;
+const size_t TabNodePool::kFreeNodesHighWatermark = 100;
 
 TabNodePool::TabNodePool(ProfileSyncService* sync_service)
     : max_used_tab_node_id_(0), sync_service_(sync_service) {}
@@ -40,17 +41,24 @@
   DCHECK_GT(sync_id, syncer::kInvalidId);
   DCHECK_GT(tab_id.id(), kInvalidTabID);
   DCHECK(syncid_tabid_map_.find(sync_id) == syncid_tabid_map_.end());
-  syncid_tabid_map_[sync_id] = tab_id.id();
+  unassociated_nodes_.insert(sync_id);
   if (max_used_tab_node_id_ < tab_node_id)
     max_used_tab_node_id_ = tab_node_id;
 }
 
 void TabNodePool::AssociateTabNode(int64 sync_id, SessionID::id_type tab_id) {
   DCHECK_GT(sync_id, 0);
-  // Remove node from free node pool and associate it with tab.
-  std::set<int64>::iterator it = free_nodes_pool_.find(sync_id);
-  DCHECK(it != free_nodes_pool_.end());
-  free_nodes_pool_.erase(it);
+  // Remove sync node if it is in unassociated nodes pool.
+  std::set<int64>::iterator u_it = unassociated_nodes_.find(sync_id);
+  if (u_it != unassociated_nodes_.end()) {
+    unassociated_nodes_.erase(u_it);
+  } else {
+    // This is a new node association, the sync node should be free.
+    // Remove node from free node pool and then associate it with the tab.
+    std::set<int64>::iterator it = free_nodes_pool_.find(sync_id);
+    DCHECK(it != free_nodes_pool_.end());
+    free_nodes_pool_.erase(it);
+  }
   DCHECK(syncid_tabid_map_.find(sync_id) == syncid_tabid_map_.end());
   syncid_tabid_map_[sync_id] = tab_id;
 }
@@ -99,30 +107,49 @@
   SyncIDToTabIDMap::iterator it = syncid_tabid_map_.find(sync_id);
   DCHECK(it != syncid_tabid_map_.end());
   syncid_tabid_map_.erase(it);
-  DCHECK(free_nodes_pool_.find(sync_id) == free_nodes_pool_.end());
+  FreeTabNodeInternal(sync_id);
+}
 
-  // If number of free nodes exceed number of maximum allowed free nodes,
-  // delete the sync node.
-  if (free_nodes_pool_.size() < kMaxNumberOfFreeNodes) {
-    free_nodes_pool_.insert(sync_id);
-  } else {
+void TabNodePool::FreeTabNodeInternal(int64 sync_id) {
+  DCHECK(free_nodes_pool_.find(sync_id) == free_nodes_pool_.end());
+  free_nodes_pool_.insert(sync_id);
+
+  // If number of free nodes exceed kFreeNodesHighWatermark,
+  // delete sync nodes till number reaches kFreeNodesLowWatermark.
+  // Note: This logic is to mitigate temporary disassociation issues with old
+  // clients: http://crbug.com/259918. Newer versions do not need this.
+  if (free_nodes_pool_.size() > kFreeNodesHighWatermark) {
     syncer::WriteTransaction trans(FROM_HERE, sync_service_->GetUserShare());
-    syncer::WriteNode tab_node(&trans);
-    if (tab_node.InitByIdLookup(sync_id) != syncer::BaseNode::INIT_OK) {
-      LOG(ERROR) << "Could not find sync node with id: " << sync_id;
-      return;
+    for (std::set<int64>::iterator free_it = free_nodes_pool_.begin();
+         free_it != free_nodes_pool_.end();) {
+      syncer::WriteNode tab_node(&trans);
+      if (tab_node.InitByIdLookup(*free_it) != syncer::BaseNode::INIT_OK) {
+        LOG(ERROR) << "Could not find sync node with id: " << *free_it;
+        return;
+      }
+      free_nodes_pool_.erase(free_it++);
+      tab_node.Tombstone();
+      if (free_nodes_pool_.size() <= kFreeNodesLowWatermark) {
+        return;
+      }
     }
-    tab_node.Tombstone();
   }
 }
 
-bool TabNodePool::ReassociateTabNode(int64 sync_id, SessionID::id_type tab_id) {
-  SyncIDToTabIDMap::iterator it = syncid_tabid_map_.find(sync_id);
-  if (it != syncid_tabid_map_.end()) {
-    syncid_tabid_map_[sync_id] = tab_id;
-    return true;
+bool TabNodePool::IsUnassociatedTabNode(int64 sync_id) {
+  return unassociated_nodes_.find(sync_id) != unassociated_nodes_.end();
+}
+
+void TabNodePool::ReassociateTabNode(int64 sync_id, SessionID::id_type tab_id) {
+  // Remove from list of unassociated sync_nodes if present.
+  std::set<int64>::iterator it = unassociated_nodes_.find(sync_id);
+  if (it != unassociated_nodes_.end()) {
+    unassociated_nodes_.erase(it);
+  } else {
+    // sync_id must be an already associated node.
+    DCHECK(syncid_tabid_map_.find(sync_id) != syncid_tabid_map_.end());
   }
-  return false;
+  syncid_tabid_map_[sync_id] = tab_id;
 }
 
 SessionID::id_type TabNodePool::GetTabIdFromSyncId(int64 sync_id) const {
@@ -133,29 +160,26 @@
   return kInvalidTabID;
 }
 
-void TabNodePool::FreeUnusedTabNodes(const std::set<int64>& used_sync_ids) {
-  for (SyncIDToTabIDMap::iterator it = syncid_tabid_map_.begin();
-       it != syncid_tabid_map_.end();) {
-    if (used_sync_ids.find(it->first) == used_sync_ids.end()) {
-      // This sync node is not used, return it to free node pool.
-      int64 sync_id = it->first;
-      ++it;
-      FreeTabNode(sync_id);
-    } else {
-      ++it;
-    }
+void TabNodePool::FreeUnassociatedTabNodes() {
+  for (std::set<int64>::iterator it = unassociated_nodes_.begin();
+       it != unassociated_nodes_.end();) {
+    FreeTabNodeInternal(*it);
+    unassociated_nodes_.erase(it++);
   }
+  DCHECK(unassociated_nodes_.empty());
 }
 
 // Clear tab pool.
 void TabNodePool::Clear() {
+  unassociated_nodes_.clear();
   free_nodes_pool_.clear();
   syncid_tabid_map_.clear();
   max_used_tab_node_id_ = 0;
 }
 
 size_t TabNodePool::Capacity() const {
-  return syncid_tabid_map_.size() + free_nodes_pool_.size();
+  return syncid_tabid_map_.size() + unassociated_nodes_.size() +
+         free_nodes_pool_.size();
 }
 
 bool TabNodePool::Empty() const { return free_nodes_pool_.empty(); }
diff --git a/chrome/browser/sync/glue/tab_node_pool.h b/chrome/browser/sync/glue/tab_node_pool.h
index 4ad3fef..7727ba3 100644
--- a/chrome/browser/sync/glue/tab_node_pool.h
+++ b/chrome/browser/sync/glue/tab_node_pool.h
@@ -29,6 +29,17 @@
 // difference is that tab_node_id is controlled by the model associator and
 // is used when creating a new sync node, which returns the sync_id, created
 // by the sync db.
+//
+// A sync node can be in one of the three states:
+// 1. Associated   : Sync node is used and associated with a tab.
+// 2. Unassociated : Sync node is used but currently unassociated with any tab.
+//                   This is true for old nodes that remain from a session
+//                   restart. Nodes are only unassociated temporarily while the
+//                   model associator figures out which tabs belong to which
+//                   nodes. Eventually any remaining unassociated nodes are
+//                   freed.
+// 3. Free         : Sync node is unused.
+
 class TabNodePool {
  public:
   explicit TabNodePool(ProfileSyncService* sync_service);
@@ -36,6 +47,14 @@
   enum InvalidTab {
     kInvalidTabID = -1
   };
+
+  // If free nodes > kFreeNodesHighWatermark, delete all free nodes until
+  // free nodes <= kFreeNodesLowWatermark.
+  static const size_t kFreeNodesLowWatermark;
+
+  // Maximum limit of FreeNodes allowed on the client.
+  static const size_t kFreeNodesHighWatermark;
+
   // Build a sync tag from tab_node_id.
   static std::string TabIdToTag(const std::string machine_tag,
                                 size_t tab_node_id);
@@ -48,40 +67,39 @@
   // associated.
   int64 GetFreeTabNode();
 
-  // Removes the node from |syncid_tabid_map_| and returns the node to free
-  // pool.
+  // Removes association for |sync_id| and returns it to the free node pool.
   void FreeTabNode(int64 sync_id);
 
-  // Removes |sync_id| from free node pool and associates it with |tab_id|.
-  // sync_id should be id of a free node. In order to associate a non free
-  // sync node, use ReassociateTabNode.
+  // Associates |sync_id| with |tab_id|. |sync_id| should either be unassociated
+  // or free. If |sync_id| is free, |sync_id| is removed from the free node pool
+  // In order to associate a non free sync node, use ReassociateTabNode.
   void AssociateTabNode(int64 sync_id, SessionID::id_type tab_id);
 
-  // Associate sync_id with tab_id but does not add it to free node pool.
+  // Adds |sync_id| as an unassociated sync node.
   // Note: this should only be called when we discover tab sync nodes from
   // previous sessions, not for freeing tab nodes we created through
   // GetFreeTabNode (use FreeTabNode below for that).
-  // The difference between AddTabNode and AssociateTabNode is that
-  // AssociateTabNode requires the sync node to be free to be associated.
-  // AddTabNode just adds the association.
   void AddTabNode(int64 sync_id, const SessionID& tab_id, size_t tab_node_id);
 
-  // Returns the tab_id for |sync_id| if it exists else returns kInvalidTabID.
+  // Returns the tab_id for |sync_id| if it is associated else returns
+  // kInvalidTabID.
   SessionID::id_type GetTabIdFromSyncId(int64 sync_id) const;
 
-  // Reassociates sync node with id |sync_id| with tab node with |tab_id|.
-  // Returns true if it is able to reassociate the node, false if a sync node
-  // with id |sync_id| is not associated with any tab.
-  bool ReassociateTabNode(int64 sync_id, SessionID::id_type tab_id);
+  // Reassociates |sync_id| with |tab_id|. |sync_id| must be either associated
+  // with a tab or in the set of unassociated nodes.
+  void ReassociateTabNode(int64 sync_id, SessionID::id_type tab_id);
 
-  // Returns any nodes with sync_ids not in |used_synced_ids| to free node pool.
-  void FreeUnusedTabNodes(const std::set<int64>& used_sync_ids);
+  // Returns true if |sync_id| is an unassociated tab node.
+  bool IsUnassociatedTabNode(int64 sync_id);
+
+  // Returns any unassociated nodes to the free node pool.
+  void FreeUnassociatedTabNodes();
 
   // Clear tab pool.
   void Clear();
 
   // Return the number of tab nodes this client currently has allocated
-  // (including both free and used nodes)
+  // (including both free, unassociated and associated nodes)
   size_t Capacity() const;
 
   // Return empty status (all tab nodes are in use).
@@ -96,6 +114,9 @@
   friend class SyncTabNodePoolTest;
   typedef std::map<int64, SessionID::id_type> SyncIDToTabIDMap;
 
+  // Adds |sync_id| to free node pool.
+  void FreeTabNodeInternal(int64 sync_id);
+
   // Stores mapping of sync_ids associated with tab_ids, these are the used
   // nodes of tab node pool.
   // The nodes in the map can be returned to free tab node pool by calling
@@ -105,6 +126,11 @@
   // The sync ids for the set of free sync nodes.
   std::set<int64> free_nodes_pool_;
 
+  // The sync ids that are added to pool using AddTabNode and are currently
+  // not associated with any tab. They can be reassociated using
+  // ReassociateTabNode.
+  std::set<int64> unassociated_nodes_;
+
   // The maximum used tab_node id for a sync node. A new sync node will always
   // be created with max_used_tab_node_id_ + 1.
   size_t max_used_tab_node_id_;
diff --git a/chrome/browser/sync/glue/tab_node_pool_unittest.cc b/chrome/browser/sync/glue/tab_node_pool_unittest.cc
index b3ee12f..4487df6 100644
--- a/chrome/browser/sync/glue/tab_node_pool_unittest.cc
+++ b/chrome/browser/sync/glue/tab_node_pool_unittest.cc
@@ -33,8 +33,8 @@
   EXPECT_EQ(1000u, GetMaxUsedTabNodeId());
   pool_.ReassociateTabNode(6, 500);
   // Freeing a tab node does not change max_used_tab_node_id_.
-  pool_.FreeTabNode(4);
-  pool_.FreeUnusedTabNodes(std::set<int64>());
+  pool_.FreeTabNode(6);
+  pool_.FreeUnassociatedTabNodes();
   EXPECT_EQ(1000u, GetMaxUsedTabNodeId());
   for (int i = 0; i < 3; ++i) {
     pool_.AssociateTabNode(pool_.GetFreeTabNode(), i + 1);
@@ -55,20 +55,16 @@
   pool_.AddTabNode(5, session_id, 2);
   EXPECT_EQ(2u, pool_.Capacity());
   EXPECT_TRUE(pool_.Empty());
-  EXPECT_TRUE(pool_.ReassociateTabNode(4, 2));
-  EXPECT_TRUE(pool_.ReassociateTabNode(5, 1));
+  EXPECT_TRUE(pool_.IsUnassociatedTabNode(4));
+  pool_.ReassociateTabNode(4, 2);
   EXPECT_TRUE(pool_.Empty());
-  // Check free unused tab nodes returns the node to free node pool_.
-  std::set<int64> used_sync_ids;
-  used_sync_ids.insert(5);
-  pool_.FreeUnusedTabNodes(used_sync_ids);
-  // 4 should be returned to free node pool_.
+  // Check FreeUnassociatedTabNodes returns the node to free node pool_.
+  pool_.FreeUnassociatedTabNodes();
+  // 5 should be returned to free node pool_.
   EXPECT_EQ(2u, pool_.Capacity());
+  // Should be able to free 4.
+  pool_.FreeTabNode(4);
   EXPECT_FALSE(pool_.Empty());
-  // 5 should still be in the associated nodes.
-  EXPECT_FALSE(pool_.Full());
-  pool_.FreeTabNode(5);
-  // 5 should be returned to free nodes pool and pool should be full.
   EXPECT_TRUE(pool_.Full());
   EXPECT_EQ(4, pool_.GetFreeTabNode());
   pool_.AssociateTabNode(4, 1);
@@ -87,24 +83,24 @@
   // sync_id = 5, tab_node_id = 2, tab_id = 2
   session_id.set_id(2);
   pool_.AddTabNode(5, session_id, 2);
-  // sync_id = 5, tab_node_id = 3, tab_id =3
+  // sync_id = 6, tab_node_id = 3, tab_id =3
   session_id.set_id(3);
   pool_.AddTabNode(6, session_id, 3);
   EXPECT_EQ(3u, pool_.Capacity());
   EXPECT_TRUE(pool_.Empty());
+  EXPECT_TRUE(pool_.IsUnassociatedTabNode(4));
+  pool_.ReassociateTabNode(4, 5);
   // Free 5 and 6.
-  pool_.FreeTabNode(5);
-  pool_.FreeTabNode(6);
-  // 5 and 6 nodes should not get reassociated.
-  EXPECT_TRUE(pool_.ReassociateTabNode(4, 5));
-  EXPECT_FALSE(pool_.ReassociateTabNode(5, 6));
-  EXPECT_FALSE(pool_.ReassociateTabNode(6, 7));
+  pool_.FreeUnassociatedTabNodes();
+  // 5 and 6 nodes should not be unassociated.
+  EXPECT_FALSE(pool_.IsUnassociatedTabNode(5));
+  EXPECT_FALSE(pool_.IsUnassociatedTabNode(6));
   // Free node pool should have 5 and 6.
   EXPECT_FALSE(pool_.Empty());
   EXPECT_EQ(3u, pool_.Capacity());
 
   // Free all nodes
-  pool_.FreeUnusedTabNodes(std::set<int64>());
+  pool_.FreeTabNode(4);
   EXPECT_TRUE(pool_.Full());
   std::set<int64> free_sync_ids;
   for (int i = 0; i < 3; ++i) {
@@ -132,7 +128,7 @@
   pool_.AddTabNode(5, session_id, 1);
   session_id.set_id(2);
   pool_.AddTabNode(10, session_id, 2);
-  pool_.FreeUnusedTabNodes(std::set<int64>());
+  pool_.FreeUnassociatedTabNodes();
   EXPECT_FALSE(pool_.Empty());
   EXPECT_TRUE(pool_.Full());
 
@@ -156,7 +152,7 @@
   session_id.set_id(2);
   pool_.AddTabNode(10, session_id, 2);
   // Free added nodes.
-  pool_.FreeUnusedTabNodes(std::set<int64>());
+  pool_.FreeUnassociatedTabNodes();
   EXPECT_FALSE(pool_.Empty());
   EXPECT_TRUE(pool_.Full());
   EXPECT_EQ(2U, pool_.Capacity());
diff --git a/chrome/browser/sync/profile_sync_service.cc b/chrome/browser/sync/profile_sync_service.cc
index 2754e65..c045d86 100644
--- a/chrome/browser/sync/profile_sync_service.cc
+++ b/chrome/browser/sync/profile_sync_service.cc
@@ -347,19 +347,10 @@
 }
 
 void ProfileSyncService::RegisterAuthNotifications() {
-  TokenService* token_service = TokenServiceFactory::GetForProfile(profile_);
-  registrar_.Add(this,
-                 chrome::NOTIFICATION_TOKEN_AVAILABLE,
-                 content::Source<TokenService>(token_service));
-  registrar_.Add(this,
-                 chrome::NOTIFICATION_TOKEN_LOADING_FINISHED,
-                 content::Source<TokenService>(token_service));
-  registrar_.Add(this,
-                 chrome::NOTIFICATION_TOKEN_REQUEST_FAILED,
-                 content::Source<TokenService>(token_service));
-  registrar_.Add(this,
-                 chrome::NOTIFICATION_TOKENS_CLEARED,
-                 content::Source<TokenService>(token_service));
+  ProfileOAuth2TokenService* token_service =
+      ProfileOAuth2TokenServiceFactory::GetForProfile(profile_);
+  token_service->AddObserver(this);
+
   registrar_.Add(this,
                  chrome::NOTIFICATION_GOOGLE_SIGNIN_SUCCESSFUL,
                  content::Source<Profile>(profile_));
@@ -368,6 +359,13 @@
                  content::Source<Profile>(profile_));
 }
 
+void ProfileSyncService::UnregisterAuthNotifications() {
+  ProfileOAuth2TokenService* token_service =
+      ProfileOAuth2TokenServiceFactory::GetForProfile(profile_);
+  token_service->RemoveObserver(this);
+  registrar_.RemoveAll();
+}
+
 void ProfileSyncService::RegisterDataTypeController(
     DataTypeController* data_type_controller) {
   DCHECK_EQ(data_type_controllers_.count(data_type_controller->type()), 0U);
@@ -681,7 +679,45 @@
   }
 }
 
+void ProfileSyncService::OnRefreshTokenAvailable(
+    const std::string& account_id) {
+  OnRefreshTokensLoaded();
+}
+
+void ProfileSyncService::OnRefreshTokenRevoked(
+    const std::string& account_id,
+    const GoogleServiceAuthError& error) {
+  if (!IsOAuthRefreshTokenAvailable()) {
+    // The additional check around IsOAuthRefreshTokenAvailable() above
+    // prevents us sounding the alarm if we actually have a valid token but
+    // a refresh attempt by TokenService failed for any variety of reasons
+    // (e.g. flaky network). It's possible the token we do have is also
+    // invalid, but in that case we should already have (or can expect) an
+    // auth error sent from the sync backend.
+    UpdateAuthErrorState(error);
+  }
+}
+
+void ProfileSyncService::OnRefreshTokensLoaded() {
+  // This notification gets fired when TokenService loads the tokens
+  // from storage.
+  // Initialize the backend if sync is enabled. If the sync token was
+  // not loaded, GetCredentials() will generate invalid credentials to
+  // cause the backend to generate an auth error (crbug.com/121755).
+  if (backend_) {
+    RequestAccessToken();
+  } else {
+    TryStart();
+  }
+}
+
+void ProfileSyncService::OnRefreshTokensCleared() {
+  access_token_.clear();
+}
+
 void ProfileSyncService::Shutdown() {
+  UnregisterAuthNotifications();
+
   if (profile_)
     SigninGlobalError::GetForProfile(profile_)->RemoveProvider(this);
 
@@ -778,14 +814,16 @@
 }
 
 void ProfileSyncService::NotifyObservers() {
-  FOR_EACH_OBSERVER(Observer, observers_, OnStateChanged());
+  FOR_EACH_OBSERVER(ProfileSyncServiceBase::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());
+  FOR_EACH_OBSERVER(ProfileSyncServiceBase::Observer, observers_,
+                    OnSyncCycleCompleted());
   sync_js_controller_.HandleJsEvent(
       "onServiceStateChanged", JsEventDetails());
 }
@@ -1898,8 +1936,6 @@
 void ProfileSyncService::Observe(int type,
                                  const content::NotificationSource& source,
                                  const content::NotificationDetails& details) {
-  const char* sync_token_service = use_oauth2_token_ ?
-      GaiaConstants::kGaiaOAuth2LoginRefreshToken : GaiaConstants::kSyncService;
   switch (type) {
     case chrome::NOTIFICATION_GOOGLE_SIGNIN_SUCCESSFUL: {
       const GoogleServiceSigninSuccessDetails* successful =
@@ -1923,58 +1959,6 @@
       }
       break;
     }
-    case chrome::NOTIFICATION_TOKEN_REQUEST_FAILED: {
-      // TODO(atwilson): sync shouldn't report refresh token request failures.
-      // TokenService should do that instead.
-      const TokenService::TokenRequestFailedDetails& token_details =
-          *(content::Details<const TokenService::TokenRequestFailedDetails>(
-              details).ptr());
-      if (token_details.service() == sync_token_service &&
-          !IsOAuthRefreshTokenAvailable()) {
-        // The additional check around IsOAuthRefreshTokenAvailable() above
-        // prevents us sounding the alarm if we actually have a valid token but
-        // a refresh attempt by TokenService failed for any variety of reasons
-        // (e.g. flaky network). It's possible the token we do have is also
-        // invalid, but in that case we should already have (or can expect) an
-        // auth error sent from the sync backend.
-        AuthError error(AuthError::INVALID_GAIA_CREDENTIALS);
-        UpdateAuthErrorState(error);
-      }
-      break;
-    }
-    case chrome::NOTIFICATION_TOKEN_AVAILABLE: {
-      // TODO(atwilson): Listen for notifications on OAuth2TokenService
-      // (crbug.com/243737)
-      const TokenService::TokenAvailableDetails& token_details =
-          *(content::Details<const TokenService::TokenAvailableDetails>(
-              details).ptr());
-      if (token_details.service() != sync_token_service)
-        break;
-    } // Fall through.
-    case chrome::NOTIFICATION_TOKEN_LOADING_FINISHED: {
-      // This notification gets fired when TokenService loads the tokens
-      // from storage.
-      // Initialize the backend if sync is enabled. If the sync token was
-      // not loaded, GetCredentials() will generate invalid credentials to
-      // cause the backend to generate an auth error (crbug.com/121755).
-      if (backend_) {
-        if (use_oauth2_token_)
-          RequestAccessToken();
-        else
-          backend_->UpdateCredentials(GetCredentials());
-      } else {
-        TryStart();
-      }
-      break;
-    }
-    case chrome::NOTIFICATION_TOKENS_CLEARED: {
-      // GetCredentials() will generate invalid credentials to cause the backend
-      // to generate an auth error.
-      access_token_.clear();
-      if (backend_)
-        backend_->UpdateCredentials(GetCredentials());
-      break;
-    }
     case chrome::NOTIFICATION_GOOGLE_SIGNED_OUT:
       sync_disabled_by_admin_ = false;
       DisableForUser();
@@ -1985,15 +1969,18 @@
   }
 }
 
-void ProfileSyncService::AddObserver(Observer* observer) {
+void ProfileSyncService::AddObserver(
+    ProfileSyncServiceBase::Observer* observer) {
   observers_.AddObserver(observer);
 }
 
-void ProfileSyncService::RemoveObserver(Observer* observer) {
+void ProfileSyncService::RemoveObserver(
+    ProfileSyncServiceBase::Observer* observer) {
   observers_.RemoveObserver(observer);
 }
 
-bool ProfileSyncService::HasObserver(Observer* observer) const {
+bool ProfileSyncService::HasObserver(
+    ProfileSyncServiceBase::Observer* observer) const {
   return observers_.HasObserver(observer);
 }
 
@@ -2031,6 +2018,9 @@
 
 void ProfileSyncService::StopAndSuppress() {
   sync_prefs_.SetStartSuppressed(true);
+  if (backend_) {
+    backend_->UnregisterInvalidationIds();
+  }
   ShutdownImpl(false);
 }
 
diff --git a/chrome/browser/sync/profile_sync_service.h b/chrome/browser/sync/profile_sync_service.h
index 18dc129..89edb3b 100644
--- a/chrome/browser/sync/profile_sync_service.h
+++ b/chrome/browser/sync/profile_sync_service.h
@@ -163,7 +163,8 @@
                            public content::NotificationObserver,
                            public BrowserContextKeyedService,
                            public browser_sync::DataTypeEncryptionHandler,
-                           public OAuth2TokenService::Consumer {
+                           public OAuth2TokenService::Consumer,
+                           public OAuth2TokenService::Observer {
  public:
   typedef browser_sync::SyncBackendHost::Status Status;
 
@@ -235,11 +236,14 @@
   virtual bool HasSyncSetupCompleted() const OVERRIDE;
   virtual bool ShouldPushChanges() OVERRIDE;
   virtual syncer::ModelTypeSet GetActiveDataTypes() const OVERRIDE;
-  virtual void AddObserver(Observer* observer) OVERRIDE;
-  virtual void RemoveObserver(Observer* observer) OVERRIDE;
-  virtual bool HasObserver(Observer* observer) const OVERRIDE;
+  virtual void AddObserver(ProfileSyncServiceBase::Observer* observer) OVERRIDE;
+  virtual void RemoveObserver(
+      ProfileSyncServiceBase::Observer* observer) OVERRIDE;
+  virtual bool HasObserver(
+      ProfileSyncServiceBase::Observer* observer) const OVERRIDE;
 
   void RegisterAuthNotifications();
+  void UnregisterAuthNotifications();
 
   // Returns true if sync is enabled/not suppressed and the user is logged in.
   // (being logged in does not mean that tokens are available - tokens may
@@ -590,7 +594,7 @@
   // The set of currently enabled sync experiments.
   const syncer::Experiments& current_experiments() const;
 
-  // OAuth2TokenService::Consumer implementation
+  // OAuth2TokenService::Consumer implementation.
   virtual void OnGetTokenSuccess(
       const OAuth2TokenService::Request* request,
       const std::string& access_token,
@@ -599,6 +603,14 @@
       const OAuth2TokenService::Request* request,
       const GoogleServiceAuthError& error) OVERRIDE;
 
+  // OAuth2TokenService::Observer implementation.
+  virtual void OnRefreshTokenAvailable(const std::string& account_id) OVERRIDE;
+  virtual void OnRefreshTokenRevoked(
+      const std::string& account_id,
+      const GoogleServiceAuthError& error) OVERRIDE;
+  virtual void OnRefreshTokensLoaded() OVERRIDE;
+  virtual void OnRefreshTokensCleared() OVERRIDE;
+
   // BrowserContextKeyedService implementation.  This must be called exactly
   // once (before this object is destroyed).
   virtual void Shutdown() OVERRIDE;
@@ -838,7 +850,7 @@
   // Manages the start and stop of the various data types.
   scoped_ptr<browser_sync::DataTypeManager> data_type_manager_;
 
-  ObserverList<Observer> observers_;
+  ObserverList<ProfileSyncServiceBase::Observer> observers_;
 
   syncer::SyncJsController sync_js_controller_;
 
diff --git a/chrome/browser/sync/profile_sync_service_android.cc b/chrome/browser/sync/profile_sync_service_android.cc
index ffefa2e..8abc53b 100644
--- a/chrome/browser/sync/profile_sync_service_android.cc
+++ b/chrome/browser/sync/profile_sync_service_android.cc
@@ -119,7 +119,7 @@
   syncer::ObjectIdSet object_ids;
   object_ids.insert(object_id);
   syncer::ObjectIdInvalidationMap object_ids_with_states =
-      syncer::ObjectIdSetToInvalidationMap(object_ids, state);
+      syncer::ObjectIdSetToInvalidationMap(object_ids, version, state);
 
   content::NotificationService::current()->Notify(
       chrome::NOTIFICATION_SYNC_REFRESH_REMOTE,
diff --git a/chrome/browser/sync/profile_sync_service_mock.h b/chrome/browser/sync/profile_sync_service_mock.h
index 128422c..ce3aec2 100644
--- a/chrome/browser/sync/profile_sync_service_mock.h
+++ b/chrome/browser/sync/profile_sync_service_mock.h
@@ -65,8 +65,8 @@
   MOCK_METHOD1(DeactivateDataType, void(syncer::ModelType));
   MOCK_METHOD0(UnsuppressAndStart, void());
 
-  MOCK_METHOD1(AddObserver, void(Observer*));
-  MOCK_METHOD1(RemoveObserver, void(Observer*));
+  MOCK_METHOD1(AddObserver, void(ProfileSyncServiceBase::Observer*));
+  MOCK_METHOD1(RemoveObserver, void(ProfileSyncServiceBase::Observer*));
   MOCK_METHOD0(GetJsController, base::WeakPtr<syncer::JsController>());
   MOCK_CONST_METHOD0(HasSyncSetupCompleted, bool());
 
diff --git a/chrome/browser/sync/profile_sync_service_session_unittest.cc b/chrome/browser/sync/profile_sync_service_session_unittest.cc
index b400e9e..6643286 100644
--- a/chrome/browser/sync/profile_sync_service_session_unittest.cc
+++ b/chrome/browser/sync/profile_sync_service_session_unittest.cc
@@ -798,7 +798,7 @@
     model_associator_->tab_pool_.AddTabNode(i + 1, session_id, i);
   }
 
-  model_associator_->tab_pool_.FreeUnusedTabNodes(std::set<int64>());
+  model_associator_->tab_pool_.FreeUnassociatedTabNodes();
   std::vector<int64> node_ids;
   ASSERT_EQ(num_starting_nodes, model_associator_->tab_pool_.Capacity());
   ASSERT_FALSE(model_associator_->tab_pool_.Empty());
@@ -1292,7 +1292,7 @@
   // Create new WebContents, with the required tab helpers.
   WebContents* new_web_contents = WebContents::CreateWithSessionStorage(
       WebContents::CreateParams(profile()),
-      old_web_contents->GetController().GetSessionStorageNamespace());
+      old_web_contents->GetController().GetSessionStorageNamespaceMap());
   SessionTabHelper::CreateForWebContents(new_web_contents);
   TabContentsSyncedTabDelegate::CreateForWebContents(new_web_contents);
   new_web_contents->GetController()
@@ -1328,4 +1328,46 @@
   ASSERT_FALSE(error.IsSet());
 }
 
+TEST_F(ProfileSyncServiceSessionTest, TabPoolFreeNodeLimits) {
+  CreateRootHelper create_root(this);
+  ASSERT_TRUE(StartSyncService(create_root.callback(), false));
+  ASSERT_TRUE(create_root.success());
+
+  // Allocate TabNodePool::kFreeNodesHighWatermark + 1 nodes and verify that
+  // freeing the last node reduces the free node pool size to
+  // kFreeNodesLowWatermark.
+
+  SessionID session_id;
+  std::vector<int64> used_sync_ids;
+  for (size_t i = 1; i <= TabNodePool::kFreeNodesHighWatermark + 1; ++i) {
+    session_id.set_id(i);
+    int64 sync_id = model_associator_->tab_pool_.GetFreeTabNode();
+    model_associator_->tab_pool_.AssociateTabNode(sync_id, i);
+    used_sync_ids.push_back(sync_id);
+  }
+
+  // Free all except one node.
+  int64 last_sync_id = used_sync_ids.back();
+  used_sync_ids.pop_back();
+
+  for (size_t i = 0; i < used_sync_ids.size(); ++i) {
+    model_associator_->tab_pool_.FreeTabNode(used_sync_ids[i]);
+  }
+
+  // Except one node all nodes should be in FreeNode pool.
+  EXPECT_FALSE(model_associator_->tab_pool_.Full());
+  EXPECT_FALSE(model_associator_->tab_pool_.Empty());
+  // Total capacity = 1 Associated Node + kFreeNodesHighWatermark free node.
+  EXPECT_EQ(TabNodePool::kFreeNodesHighWatermark + 1,
+            model_associator_->tab_pool_.Capacity());
+
+  // Freeing the last sync node should drop the free nodes to
+  // kFreeNodesLowWatermark.
+  model_associator_->tab_pool_.FreeTabNode(last_sync_id);
+  EXPECT_FALSE(model_associator_->tab_pool_.Empty());
+  EXPECT_TRUE(model_associator_->tab_pool_.Full());
+  EXPECT_EQ(TabNodePool::kFreeNodesLowWatermark,
+            model_associator_->tab_pool_.Capacity());
+}
+
 }  // namespace browser_sync
diff --git a/chrome/browser/sync/test/integration/sync_test.cc b/chrome/browser/sync/test/integration/sync_test.cc
index c8cf87c..ff6ed2c 100644
--- a/chrome/browser/sync/test/integration/sync_test.cc
+++ b/chrome/browser/sync/test/integration/sync_test.cc
@@ -671,7 +671,9 @@
           "from_server",
           syncer::NOTIFY_ALL,
           syncer::ObjectIdSetToInvalidationMap(
-              syncer::ModelTypeSetToObjectIdSet(changed_types), std::string())
+              syncer::ModelTypeSetToObjectIdSet(changed_types),
+              syncer::Invalidation::kUnknownVersion,
+              std::string())
           ).ToString();
   const std::string& path =
       std::string("chromiumsync/sendnotification?channel=") +
diff --git a/chrome/browser/sync/test_profile_sync_service.cc b/chrome/browser/sync/test_profile_sync_service.cc
index 2fefd29..499d2be 100644
--- a/chrome/browser/sync/test_profile_sync_service.cc
+++ b/chrome/browser/sync/test_profile_sync_service.cc
@@ -327,8 +327,7 @@
     content::BrowserContext* context) {
   Profile* profile = static_cast<Profile*>(context);
 
-  FakeOAuth2TokenService* service =
-      new FakeOAuth2TokenService(context->GetRequestContext());
+  FakeOAuth2TokenService* service = new FakeOAuth2TokenService();
   service->Initialize(profile);
   return service;
 }
diff --git a/chrome/browser/sync/test_profile_sync_service.h b/chrome/browser/sync/test_profile_sync_service.h
index 41d2687..3322258 100644
--- a/chrome/browser/sync/test_profile_sync_service.h
+++ b/chrome/browser/sync/test_profile_sync_service.h
@@ -193,9 +193,6 @@
 
 class FakeOAuth2TokenService : public ProfileOAuth2TokenService {
  public:
-  explicit FakeOAuth2TokenService(net::URLRequestContextGetter* getter)
-      : ProfileOAuth2TokenService(getter) {}
-
   virtual scoped_ptr<OAuth2TokenService::Request> StartRequest(
       const OAuth2TokenService::ScopeSet& scopes,
       OAuth2TokenService::Consumer* consumer) OVERRIDE;
diff --git a/chrome/browser/sync_file_system/drive_backend/metadata_database.cc b/chrome/browser/sync_file_system/drive_backend/metadata_database.cc
index 468632e..5440d98 100644
--- a/chrome/browser/sync_file_system/drive_backend/metadata_database.cc
+++ b/chrome/browser/sync_file_system/drive_backend/metadata_database.cc
@@ -55,6 +55,57 @@
   return str;
 }
 
+base::FilePath ReverseConcatPathComponents(
+    const std::vector<base::FilePath>& components) {
+  if (components.empty())
+    return base::FilePath(FILE_PATH_LITERAL("/")).NormalizePathSeparators();
+
+  size_t total_size = 0;
+  typedef std::vector<base::FilePath> PathComponents;
+  for (PathComponents::const_iterator itr = components.begin();
+       itr != components.end(); ++itr)
+    total_size += itr->value().size() + 1;
+
+  base::FilePath::StringType result;
+  result.reserve(total_size);
+  for (PathComponents::const_reverse_iterator itr = components.rbegin();
+       itr != components.rend(); ++itr) {
+    result.append(1, base::FilePath::kSeparators[0]);
+    result.append(itr->value());
+  }
+
+  return base::FilePath(result).NormalizePathSeparators();
+}
+
+void PopulateFileDetailsFromFileResource(
+    int64 change_id,
+    const google_apis::FileResource& file_resource,
+    DriveFileMetadata::Details* details) {
+  details->set_change_id(change_id);
+  for (ScopedVector<google_apis::ParentReference>::const_iterator itr =
+           file_resource.parents().begin();
+       itr != file_resource.parents().end();
+       ++itr) {
+    details->add_parent_folder_id((*itr)->file_id());
+  }
+  details->set_title(file_resource.title());
+
+  google_apis::DriveEntryKind kind = file_resource.GetKind();
+  if (kind == google_apis::ENTRY_KIND_FILE)
+    details->set_kind(KIND_FILE);
+  else if (kind == google_apis::ENTRY_KIND_FOLDER)
+    details->set_kind(KIND_FOLDER);
+  else
+    details->set_kind(KIND_UNSUPPORTED);
+
+  details->set_md5(file_resource.md5_checksum());
+  details->set_etag(file_resource.etag());
+  details->set_creation_time(file_resource.created_date().ToInternalValue());
+  details->set_modification_time(
+      file_resource.modified_date().ToInternalValue());
+  details->set_deleted(false);
+}
+
 void AdaptLevelDBStatusToSyncStatusCode(const SyncStatusCallback& callback,
                                         const leveldb::Status& status) {
   callback.Run(LevelDBStatusToSyncStatusCode(status));
@@ -251,7 +302,7 @@
       unvisited_files.erase(found);
       reachable_files.push_back(metadata);
 
-      if (!metadata->active())
+      if (!metadata->active() && !metadata->is_app_root())
         continue;
     }
 
@@ -449,14 +500,75 @@
 
 bool MetadataDatabase::BuildPathForFile(const std::string& file_id,
                                         base::FilePath* path) const {
-  NOTIMPLEMENTED();
-  return false;
+  DriveFileMetadata current;
+  if (!FindFileByFileID(file_id, &current) || !current.active())
+    return false;
+
+  std::vector<base::FilePath> components;
+  while (!current.is_app_root()) {
+    components.push_back(base::FilePath::FromUTF8Unsafe(
+        current.synced_details().title()));
+    if (!FindFileByFileID(current.parent_folder_id(), &current) ||
+        !current.active())
+      return false;
+  }
+
+  if (path)
+    *path = ReverseConcatPathComponents(components);
+
+  return true;
 }
 
 void MetadataDatabase::UpdateByChangeList(
     ScopedVector<google_apis::ChangeResource> changes,
     const SyncStatusCallback& callback) {
-  NOTIMPLEMENTED();
+  scoped_ptr<leveldb::WriteBatch> batch(new leveldb::WriteBatch);
+
+  for (ScopedVector<google_apis::ChangeResource>::iterator itr =
+           changes.begin();
+       itr != changes.end();
+       ++itr) {
+    const google_apis::ChangeResource& change = **itr;
+    DriveFileMetadata file;
+
+    // If the remote file already has an entry in the database, update its
+    // |remote_detais| and mark it dirty.
+    if (FindFileByFileID(change.file_id(), NULL)) {
+      const google_apis::FileResource* file_resource = NULL;
+      if (!change.is_deleted())
+        file_resource = change.file();
+      UpdateRemoteDetails(change.change_id(), change.file_id(), file_resource,
+                          batch.get());
+      continue;
+    }
+
+    // Deletion of an unknown file can be safely ignorable.
+    if (change.is_deleted())
+      continue;
+
+    // Find first active parent.
+    std::string parent_folder_id;
+    DriveFileMetadata parent;
+    for (ScopedVector<google_apis::ParentReference>::const_iterator itr =
+             change.file()->parents().begin();
+         itr != change.file()->parents().end();
+         ++itr) {
+      if (FindFileByFileID((*itr)->file_id(), &parent) &&
+          (parent.active() || parent.is_app_root())) {
+        parent_folder_id = parent.file_id();
+        break;
+      }
+    }
+
+    // If the remote file doesn't have active parent, ignore the file.
+    if (parent_folder_id.empty())
+      continue;
+
+    RegisterNewFile(change.change_id(), parent, *change.file(),
+                    batch.get());
+  }
+
+  WriteToDatabase(batch.Pass(), callback);
 }
 
 void MetadataDatabase::PopulateFolder(
@@ -696,6 +808,56 @@
   dirty_files_.erase(file.get());
 }
 
+void MetadataDatabase::UpdateRemoteDetails(
+    int64 change_id,
+    const std::string& file_id,
+    const google_apis::FileResource* file_resource,
+    leveldb::WriteBatch* batch) {
+  DriveFileMetadata* file = file_by_file_id_[file_id];
+
+  file->clear_remote_details();
+  DriveFileMetadata::Details* details = file->mutable_remote_details();
+  if (file_resource) {
+    PopulateFileDetailsFromFileResource(change_id, *file_resource, details);
+  } else {
+    details->set_deleted(true);
+    details->set_change_id(change_id);
+  }
+
+  file->set_dirty(true);
+  PutFileToBatch(*file, batch);
+
+  dirty_files_.insert(file);
+}
+
+void MetadataDatabase::RegisterNewFile(
+    int64 change_id,
+    const DriveFileMetadata& parent_folder,
+    const google_apis::FileResource& new_file_resource,
+    leveldb::WriteBatch* batch) {
+  scoped_ptr<DriveFileMetadata> file(new DriveFileMetadata);
+  std::string file_id = new_file_resource.file_id();
+  file->set_file_id(file_id);
+  file->set_parent_folder_id(parent_folder.file_id());
+  file->set_app_id(parent_folder.app_id());
+  file->set_is_app_root(false);
+
+  PopulateFileDetailsFromFileResource(
+      change_id, new_file_resource, file->mutable_remote_details());
+
+  file->set_dirty(true);
+  file->set_active(false);
+  file->set_needs_folder_listing(
+      new_file_resource.GetKind() == google_apis::ENTRY_KIND_FOLDER);
+
+  PutFileToBatch(*file, batch);
+
+  files_by_parent_[parent_folder.file_id()].insert(file.get());
+  dirty_files_.insert(file.get());
+
+  file_by_file_id_[file_id] = file.release();
+}
+
 void MetadataDatabase::WriteToDatabase(scoped_ptr<leveldb::WriteBatch> batch,
                                        const SyncStatusCallback& callback) {
   base::PostTaskAndReplyWithResult(
diff --git a/chrome/browser/sync_file_system/drive_backend/metadata_database.h b/chrome/browser/sync_file_system/drive_backend/metadata_database.h
index a248f9a..205a1cc 100644
--- a/chrome/browser/sync_file_system/drive_backend/metadata_database.h
+++ b/chrome/browser/sync_file_system/drive_backend/metadata_database.h
@@ -191,14 +191,22 @@
   void RegisterFolderAsAppRoot(const std::string& app_id,
                                const std::string& folder,
                                leveldb::WriteBatch* batch);
-  void MakeFileActive(const std::string& file,
+  void MakeFileActive(const std::string& file_id,
                       leveldb::WriteBatch* batch);
-  void MakeFileInactive(const std::string& file,
+  void MakeFileInactive(const std::string& file_id,
                         leveldb::WriteBatch* batch);
   void UnregisterFolderAsAppRoot(const std::string& app_id,
                                  leveldb::WriteBatch* batch);
-  void RemoveFile(const std::string& file,
+  void RemoveFile(const std::string& file_id,
                   leveldb::WriteBatch* batch);
+  void UpdateRemoteDetails(int64 change_id,
+                           const std::string& file_id,
+                           const google_apis::FileResource* file,
+                           leveldb::WriteBatch* batch);
+  void RegisterNewFile(int64 change_id,
+                       const DriveFileMetadata& parent_folder,
+                       const google_apis::FileResource& new_file,
+                       leveldb::WriteBatch* batch);
 
   void WriteToDatabase(scoped_ptr<leveldb::WriteBatch> batch,
                        const SyncStatusCallback& callback);
diff --git a/chrome/browser/sync_file_system/drive_backend/metadata_database_unittest.cc b/chrome/browser/sync_file_system/drive_backend/metadata_database_unittest.cc
index d8fa77d..0d2d234 100644
--- a/chrome/browser/sync_file_system/drive_backend/metadata_database_unittest.cc
+++ b/chrome/browser/sync_file_system/drive_backend/metadata_database_unittest.cc
@@ -9,11 +9,14 @@
 #include "base/message_loop/message_loop.h"
 #include "base/message_loop/message_loop_proxy.h"
 #include "base/strings/string_number_conversions.h"
+#include "chrome/browser/google_apis/drive_api_parser.h"
 #include "chrome/browser/sync_file_system/drive_backend/metadata_database.pb.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"
 
+#define FPL(a) FILE_PATH_LITERAL(a)
+
 namespace sync_file_system {
 namespace drive_backend {
 
@@ -28,74 +31,83 @@
 const int64 kInitialChangeID = 1234;
 const char kSyncRootFolderID[] = "sync_root_folder_id";
 
-bool AreEquivalentMessages(const google::protobuf::MessageLite& left,
-                           const google::protobuf::MessageLite& right);
-bool AreEquivalent(const google::protobuf::MessageLite* left,
-                   const google::protobuf::MessageLite* right) {
-  return AreEquivalentMessages(*left, *right);
+void ExpectEquivalent(const DriveFileMetadata::Details* left,
+                      const DriveFileMetadata::Details* right) {
+  EXPECT_EQ(left->title(), right->title());
+  EXPECT_EQ(left->kind(), right->kind());
+  EXPECT_EQ(left->md5(), right->md5());
+  EXPECT_EQ(left->etag(), right->etag());
+  EXPECT_EQ(left->creation_time(), right->creation_time());
+  EXPECT_EQ(left->modification_time(), right->modification_time());
+  EXPECT_EQ(left->deleted(), right->deleted());
+  EXPECT_EQ(left->change_id(), right->change_id());
+}
+
+void ExpectEquivalent(const DriveFileMetadata* left,
+                      const DriveFileMetadata* right) {
+  EXPECT_EQ(left->file_id(), right->file_id());
+  EXPECT_EQ(left->parent_folder_id(), right->parent_folder_id());
+  EXPECT_EQ(left->app_id(), right->app_id());
+  EXPECT_EQ(left->is_app_root(), right->is_app_root());
+
+  {
+    SCOPED_TRACE("Expect equivalent synced_details.");
+    ExpectEquivalent(&left->synced_details(), &right->synced_details());
+  }
+
+  {
+    SCOPED_TRACE("Expect equivalent remote_details.");
+    ExpectEquivalent(&left->remote_details(), &right->remote_details());
+  }
+
+  EXPECT_EQ(left->dirty(), right->dirty());
+  EXPECT_EQ(left->active(), right->active());
+  EXPECT_EQ(left->needs_folder_listing(), right->needs_folder_listing());
 }
 
 template <typename Container>
-bool AreEquivalentMaps(const Container& left, const Container& right);
+void ExpectEquivalentMaps(const Container& left, const Container& right);
 template <typename Key, typename Value, typename Compare>
-bool AreEquivalent(const std::map<Key, Value, Compare>& left,
-                   const std::map<Key, Value, Compare>& right) {
-  return AreEquivalentMaps(left, right);
+void ExpectEquivalent(const std::map<Key, Value, Compare>& left,
+                      const std::map<Key, Value, Compare>& right) {
+  ExpectEquivalentMaps(left, right);
 }
 
 template <typename Container>
-bool AreEquivalentSets(const Container& left, const Container& right);
+void ExpectEquivalentSets(const Container& left, const Container& right);
 template <typename Value, typename Compare>
-bool AreEquivalent(const std::set<Value, Compare>& left,
-                   const std::set<Value, Compare>& right) {
-  return AreEquivalentSets(left, right);
-}
-
-bool AreEquivalentMessages(const google::protobuf::MessageLite& left,
-                           const google::protobuf::MessageLite& right) {
-  std::string serialized_left;
-  std::string serialized_right;
-  left.SerializeToString(&serialized_left);
-  right.SerializeToString(&serialized_right);
-  return serialized_left == serialized_right;
+void ExpectEquivalent(const std::set<Value, Compare>& left,
+                      const std::set<Value, Compare>& right) {
+  return ExpectEquivalentSets(left, right);
 }
 
 template <typename Container>
-bool AreEquivalentMaps(const Container& left, const Container& right) {
-  if (left.size() != right.size())
-    return false;
-
-  typedef typename Container::const_iterator const_iterator;
-  const_iterator left_itr = left.begin();
-  const_iterator right_itr = right.begin();
-
-  while (left_itr != left.end()) {
-    if (left_itr->first != right_itr->first)
-      return false;
-    if (!AreEquivalent(left_itr->second, right_itr->second))
-      return false;
-
-    ++left_itr;
-    ++right_itr;
-  }
-  return true;
-}
-
-template <typename Container>
-bool AreEquivalentSets(const Container& left, const Container& right) {
-  if (left.size() != right.size())
-    return false;
+void ExpectEquivalentMaps(const Container& left, const Container& right) {
+  ASSERT_EQ(left.size(), right.size());
 
   typedef typename Container::const_iterator const_iterator;
   const_iterator left_itr = left.begin();
   const_iterator right_itr = right.begin();
   while (left_itr != left.end()) {
-    if (!AreEquivalent(*left_itr, *right_itr))
-      return false;
+    EXPECT_EQ(left_itr->first, right_itr->first);
+    ExpectEquivalent(left_itr->second, right_itr->second);
     ++left_itr;
     ++right_itr;
   }
-  return true;
+}
+
+template <typename Container>
+void ExpectEquivalentSets(const Container& left, const Container& right) {
+  ASSERT_EQ(left.size(), right.size());
+
+  typedef typename Container::const_iterator const_iterator;
+  const_iterator left_itr = left.begin();
+  const_iterator right_itr = right.begin();
+  while (left_itr != left.end()) {
+    ExpectEquivalent(*left_itr, *right_itr);
+    ++left_itr;
+    ++right_itr;
+  }
 }
 
 void SyncStatusResultCallback(SyncStatusCode* status_out,
@@ -117,7 +129,10 @@
 
 class MetadataDatabaseTest : public testing::Test {
  public:
-  MetadataDatabaseTest() : next_file_id_number_(1) {}
+  MetadataDatabaseTest()
+      : next_change_id_(kInitialChangeID + 1),
+        next_file_id_number_(1),
+        next_md5_sequence_number_(1) {}
 
   virtual ~MetadataDatabaseTest() {}
 
@@ -132,7 +147,7 @@
     return "file_id_" + base::Int64ToString(next_file_id_number_++);
   }
 
-  SyncStatusCode InitializeDatabase() {
+  SyncStatusCode InitializeMetadataDatabase() {
     SyncStatusCode status = SYNC_STATUS_UNKNOWN;
     MetadataDatabase::Create(base::MessageLoopProxy::current(),
                              database_dir_.path(),
@@ -155,7 +170,7 @@
     return metadata_database_->db_.get();
   }
 
-  scoped_ptr<leveldb::DB> OpenLevelDB() {
+  scoped_ptr<leveldb::DB> InitializeLevelDB() {
     leveldb::DB* db = NULL;
     leveldb::Options options;
     options.create_if_missing = true;
@@ -163,6 +178,10 @@
     leveldb::Status status =
         leveldb::DB::Open(options, database_dir_.path().AsUTF8Unsafe(), &db);
     EXPECT_TRUE(status.ok());
+
+    db->Put(leveldb::WriteOptions(), "VERSION", base::Int64ToString(3));
+    SetUpServiceMetadata(db);
+
     return make_scoped_ptr(db);
   }
 
@@ -175,45 +194,52 @@
     db->Put(leveldb::WriteOptions(), "SERVICE", value);
   }
 
-  DriveFileMetadata CreateSyncRoot() {
-    DriveFileMetadata metadata;
-    metadata.set_file_id(kSyncRootFolderID);
-    metadata.set_parent_folder_id(std::string());
-    metadata.mutable_synced_details()->set_title("Chrome Syncable FileSystem");
-    metadata.mutable_synced_details()->set_kind(KIND_FOLDER);
-    metadata.set_active(true);
-    metadata.set_dirty(false);
-    return metadata;
+  DriveFileMetadata CreateSyncRootMetadata() {
+    DriveFileMetadata sync_root;
+    sync_root.set_file_id(kSyncRootFolderID);
+    sync_root.set_parent_folder_id(std::string());
+    sync_root.mutable_synced_details()->set_title("Chrome Syncable FileSystem");
+    sync_root.mutable_synced_details()->set_kind(KIND_FOLDER);
+    sync_root.set_active(true);
+    sync_root.set_dirty(false);
+    return sync_root;
   }
 
-  DriveFileMetadata CreateUnknownFile(const std::string& app_id,
-                                      const std::string& parent_folder_id) {
-    DriveFileMetadata metadata;
-    metadata.set_file_id(GenerateFileID());
-    metadata.set_parent_folder_id(parent_folder_id);
-    metadata.set_app_id(app_id);
-    metadata.set_is_app_root(
-        !app_id.empty() && parent_folder_id == kSyncRootFolderID);
-    return metadata;
+  DriveFileMetadata CreateAppRootMetadata(const DriveFileMetadata& sync_root,
+                                          const std::string& app_id) {
+    DriveFileMetadata app_root(
+        CreateFolderMetadata(sync_root, app_id /* title */));
+    app_root.set_app_id(app_id);
+    app_root.set_is_app_root(true);
+    return app_root;
   }
 
-  DriveFileMetadata CreateFile(const std::string& app_id,
-                               const std::string& parent_folder_id,
-                               const std::string& title) {
-    DriveFileMetadata file(CreateUnknownFile(app_id, parent_folder_id));
-    file.mutable_synced_details()->add_parent_folder_id(parent_folder_id);
+  DriveFileMetadata CreateUnknownFileMetadata(const DriveFileMetadata& parent) {
+    DriveFileMetadata file;
+    file.set_file_id(GenerateFileID());
+    file.set_parent_folder_id(parent.file_id());
+    file.set_app_id(parent.app_id());
+    file.set_is_app_root(false);
+    return file;
+  }
+
+  DriveFileMetadata CreateFileMetadata(const DriveFileMetadata& parent,
+                                       const std::string& title) {
+    DriveFileMetadata file(CreateUnknownFileMetadata(parent));
+    file.mutable_synced_details()->add_parent_folder_id(parent.file_id());
     file.mutable_synced_details()->set_title(title);
     file.mutable_synced_details()->set_kind(KIND_FILE);
+    file.mutable_synced_details()->set_md5(
+        "md5_value_" + base::Int64ToString(next_md5_sequence_number_++));
     file.set_active(true);
     file.set_dirty(false);
     return file;
   }
 
-  DriveFileMetadata CreateFolder(const std::string& app_id,
-                                 const std::string& parent_folder_id,
-                                 const std::string& title) {
-    DriveFileMetadata folder(CreateUnknownFile(app_id, parent_folder_id));
-    folder.mutable_synced_details()->add_parent_folder_id(parent_folder_id);
+  DriveFileMetadata CreateFolderMetadata(const DriveFileMetadata& parent,
+                                         const std::string& title) {
+    DriveFileMetadata folder(CreateUnknownFileMetadata(parent));
+    folder.mutable_synced_details()->add_parent_folder_id(parent.file_id());
     folder.mutable_synced_details()->set_title(title);
     folder.mutable_synced_details()->set_kind(KIND_FOLDER);
     folder.set_active(true);
@@ -221,6 +247,93 @@
     return folder;
   }
 
+  scoped_ptr<google_apis::ChangeResource> CreateChangeResourceFromMetadata(
+      const DriveFileMetadata& file) {
+    scoped_ptr<google_apis::ChangeResource> change(
+        new google_apis::ChangeResource);
+    change->set_change_id(file.remote_details().change_id());
+    change->set_file_id(file.file_id());
+    change->set_deleted(file.remote_details().deleted());
+    if (change->is_deleted())
+      return change.Pass();
+
+    scoped_ptr<google_apis::FileResource> file_resource(
+        new google_apis::FileResource);
+    ScopedVector<google_apis::ParentReference> parents;
+    for (int i = 0; i < file.remote_details().parent_folder_id_size(); ++i) {
+      scoped_ptr<google_apis::ParentReference> parent(
+          new google_apis::ParentReference);
+      parent->set_file_id(file.remote_details().parent_folder_id(i));
+      parents.push_back(parent.release());
+    }
+
+    file_resource->set_file_id(file.file_id());
+    file_resource->set_parents(&parents);
+    file_resource->set_title(file.remote_details().title());
+    if (file.remote_details().kind() == KIND_FOLDER)
+      file_resource->set_mime_type("application/vnd.google-apps.folder");
+    else if (file.remote_details().kind() == KIND_FILE)
+      file_resource->set_mime_type("text/plain");
+    else
+      file_resource->set_mime_type("application/vnd.google-apps.document");
+    file_resource->set_md5_checksum(file.remote_details().md5());
+    file_resource->set_etag(file.remote_details().etag());
+    file_resource->set_created_date(base::Time::FromInternalValue(
+        file.remote_details().creation_time()));
+    file_resource->set_modified_date(base::Time::FromInternalValue(
+        file.remote_details().modification_time()));
+
+    change->set_file(file_resource.Pass());
+    return change.Pass();
+  }
+
+  void ApplyRenameChangeToMetadata(const std::string& new_title,
+                                   DriveFileMetadata* file) {
+    DriveFileMetadata::Details* details = file->mutable_remote_details();
+    *details = file->synced_details();
+    details->set_title(new_title);
+    details->set_change_id(next_change_id_++);
+    file->set_dirty(true);
+  }
+
+  void ApplyReorganizeChangeToMetadata(const std::string& new_parent,
+                                       DriveFileMetadata* file) {
+    DriveFileMetadata::Details* details = file->mutable_remote_details();
+    *details = file->synced_details();
+    details->clear_parent_folder_id();
+    details->add_parent_folder_id(new_parent);
+    details->set_change_id(next_change_id_++);
+    file->set_dirty(true);
+  }
+
+  void ApplyContentChangeToMetadata(DriveFileMetadata* file) {
+    DriveFileMetadata::Details* details = file->mutable_remote_details();
+    *details = file->synced_details();
+    details->set_md5(
+        "md5_value_" + base::Int64ToString(next_md5_sequence_number_++));
+    details->set_change_id(next_change_id_++);
+    file->set_dirty(true);
+  }
+
+  void ApplyNoopChangeToMetadata(DriveFileMetadata* file) {
+    *file->mutable_remote_details() = file->synced_details();
+    file->mutable_remote_details()->set_change_id(next_change_id_++);
+    file->set_dirty(true);
+  }
+
+  void ApplyNewFileChangeToMetadata(DriveFileMetadata* file) {
+    *file->mutable_remote_details() = file->synced_details();
+    file->clear_synced_details();
+    file->mutable_remote_details()->set_change_id(next_change_id_++);
+    file->set_active(false);
+    file->set_dirty(true);
+  }
+
+  void PushToChangeList(scoped_ptr<google_apis::ChangeResource> change,
+                        ScopedVector<google_apis::ChangeResource>* changes) {
+    changes->push_back(change.release());
+  }
+
   leveldb::Status PutFileToDB(leveldb::DB* db, const DriveFileMetadata& file) {
     std::string key = "FILE: " + file.file_id();
     std::string value;
@@ -236,24 +349,45 @@
                   &metadata_database_2));
     metadata_database_->db_ = metadata_database_2->db_.Pass();
 
-    EXPECT_TRUE(AreEquivalent(metadata_database_->file_by_file_id_,
-                              metadata_database_2->file_by_file_id_));
-    EXPECT_TRUE(AreEquivalent(metadata_database_->files_by_parent_,
-                              metadata_database_2->files_by_parent_));
-    EXPECT_TRUE(AreEquivalent(metadata_database_->app_root_by_app_id_,
-                              metadata_database_2->app_root_by_app_id_));
-    EXPECT_TRUE(AreEquivalent(
-        metadata_database_->active_file_by_parent_and_title_,
-        metadata_database_2->active_file_by_parent_and_title_));
-    EXPECT_TRUE(AreEquivalent(metadata_database_->dirty_files_,
-                              metadata_database_2->dirty_files_));
+    {
+      SCOPED_TRACE("Expect equivalent file_by_file_id_ contents.");
+      ExpectEquivalent(metadata_database_->file_by_file_id_,
+                       metadata_database_2->file_by_file_id_);
+    }
+
+    {
+      SCOPED_TRACE("Expect equivalent files_by_parent_ contents.");
+      ExpectEquivalent(metadata_database_->files_by_parent_,
+                       metadata_database_2->files_by_parent_);
+    }
+
+    {
+      SCOPED_TRACE("Expect equivalent app_root_by_app_id_ contents.");
+      ExpectEquivalent(metadata_database_->app_root_by_app_id_,
+                       metadata_database_2->app_root_by_app_id_);
+    }
+
+    {
+      SCOPED_TRACE("Expect equivalent"
+                   " active_file_by_parent_and_title_ contents.");
+      ExpectEquivalent(metadata_database_->active_file_by_parent_and_title_,
+                       metadata_database_2->active_file_by_parent_and_title_);
+    }
+
+    {
+      SCOPED_TRACE("Expect equivalent dirty_files_ contents.");
+      ExpectEquivalent(metadata_database_->dirty_files_,
+                       metadata_database_2->dirty_files_);
+    }
   }
 
   void VerifyFile(const DriveFileMetadata& file) {
     DriveFileMetadata file_in_metadata_db;
     ASSERT_TRUE(metadata_database()->FindFileByFileID(
         file.file_id(), &file_in_metadata_db));
-    EXPECT_TRUE(AreEquivalentMessages(file, file_in_metadata_db));
+
+    SCOPED_TRACE("Expect equivalent " + file.file_id());
+    ExpectEquivalent(&file, &file_in_metadata_db);
   }
 
   SyncStatusCode RegisterApp(const std::string& app_id,
@@ -290,38 +424,49 @@
     return status;
   }
 
+  SyncStatusCode UpdateByChangeList(
+      ScopedVector<google_apis::ChangeResource> changes) {
+    SyncStatusCode status = SYNC_STATUS_UNKNOWN;
+    metadata_database_->UpdateByChangeList(
+        changes.Pass(), base::Bind(&SyncStatusResultCallback, &status));
+    message_loop_.RunUntilIdle();
+    return status;
+  }
+
  private:
+
   base::ScopedTempDir database_dir_;
   base::MessageLoop message_loop_;
 
   scoped_ptr<MetadataDatabase> metadata_database_;
 
+  int64 next_change_id_;
   int64 next_file_id_number_;
+  int64 next_md5_sequence_number_;
 
   DISALLOW_COPY_AND_ASSIGN(MetadataDatabaseTest);
 };
 
 TEST_F(MetadataDatabaseTest, InitializationTest_Empty) {
-  EXPECT_EQ(SYNC_STATUS_OK, InitializeDatabase());
+  EXPECT_EQ(SYNC_STATUS_OK, InitializeMetadataDatabase());
   DropDatabase();
-  EXPECT_EQ(SYNC_STATUS_OK, InitializeDatabase());
+  EXPECT_EQ(SYNC_STATUS_OK, InitializeMetadataDatabase());
 }
 
 TEST_F(MetadataDatabaseTest, InitializationTest_SimpleTree) {
   std::string app_id = "app_id";
-  DriveFileMetadata sync_root(CreateSyncRoot());
-  DriveFileMetadata app_root(CreateFolder(app_id, kSyncRootFolderID, app_id));
-  DriveFileMetadata file(CreateFile(app_id, app_root.file_id(), "file"));
-  DriveFileMetadata folder(CreateFolder(app_id, app_root.file_id(), "folder"));
+  DriveFileMetadata sync_root(CreateSyncRootMetadata());
+  DriveFileMetadata app_root(CreateAppRootMetadata(sync_root, "app_id"));
+  DriveFileMetadata file(CreateFileMetadata(app_root, "file"));
+  DriveFileMetadata folder(CreateFolderMetadata(app_root, "folder"));
   DriveFileMetadata file_in_folder(
-      CreateFile(app_id, folder.file_id(), "file_in_folder"));
-  DriveFileMetadata orphaned(CreateUnknownFile(std::string(), "root"));
+      CreateFileMetadata(folder, "file_in_folder"));
+  DriveFileMetadata orphaned(CreateUnknownFileMetadata(sync_root));
+  orphaned.set_parent_folder_id(std::string());
 
   {
-    scoped_ptr<leveldb::DB> db = OpenLevelDB();
+    scoped_ptr<leveldb::DB> db = InitializeLevelDB();
     ASSERT_TRUE(db);
-    db->Put(leveldb::WriteOptions(), "VERSION", base::Int64ToString(3));
-    SetUpServiceMetadata(db.get());
 
     EXPECT_TRUE(PutFileToDB(db.get(), sync_root).ok());
     EXPECT_TRUE(PutFileToDB(db.get(), app_root).ok());
@@ -331,7 +476,7 @@
     EXPECT_TRUE(PutFileToDB(db.get(), orphaned).ok());
   }
 
-  EXPECT_EQ(SYNC_STATUS_OK, InitializeDatabase());
+  EXPECT_EQ(SYNC_STATUS_OK, InitializeMetadataDatabase());
 
   VerifyFile(sync_root);
   VerifyFile(app_root);
@@ -342,25 +487,21 @@
 }
 
 TEST_F(MetadataDatabaseTest, AppManagementTest) {
-  DriveFileMetadata sync_root(CreateSyncRoot());
-  DriveFileMetadata app_root(
-      CreateFolder("app_id", kSyncRootFolderID, "app_id"));
-  DriveFileMetadata folder(
-      CreateFolder(std::string(), kSyncRootFolderID, "folder"));
+  DriveFileMetadata sync_root(CreateSyncRootMetadata());
+  DriveFileMetadata app_root(CreateAppRootMetadata(sync_root, "app_id"));
+  DriveFileMetadata folder(CreateFolderMetadata(sync_root, "folder"));
   folder.set_active(false);
 
   {
-    scoped_ptr<leveldb::DB> db = OpenLevelDB();
+    scoped_ptr<leveldb::DB> db = InitializeLevelDB();
     ASSERT_TRUE(db);
-    db->Put(leveldb::WriteOptions(), "VERSION", base::Int64ToString(3));
-    SetUpServiceMetadata(db.get());
 
     EXPECT_TRUE(PutFileToDB(db.get(), sync_root).ok());
     EXPECT_TRUE(PutFileToDB(db.get(), app_root).ok());
     EXPECT_TRUE(PutFileToDB(db.get(), folder).ok());
   }
 
-  EXPECT_EQ(SYNC_STATUS_OK, InitializeDatabase());
+  EXPECT_EQ(SYNC_STATUS_OK, InitializeMetadataDatabase());
   VerifyFile(sync_root);
   VerifyFile(app_root);
   VerifyFile(folder);
@@ -393,5 +534,95 @@
   VerifyReloadConsistency();
 }
 
+TEST_F(MetadataDatabaseTest, BuildPathTest) {
+  DriveFileMetadata sync_root(CreateSyncRootMetadata());
+  DriveFileMetadata app_root(
+      CreateAppRootMetadata(sync_root, "app_id"));
+  DriveFileMetadata folder(CreateFolderMetadata(app_root, "folder"));
+  DriveFileMetadata file(CreateFolderMetadata(folder, "file"));
+  DriveFileMetadata inactive_folder(CreateFolderMetadata(app_root, "folder"));
+
+  {
+    scoped_ptr<leveldb::DB> db = InitializeLevelDB();
+    ASSERT_TRUE(db);
+
+    EXPECT_TRUE(PutFileToDB(db.get(), sync_root).ok());
+    EXPECT_TRUE(PutFileToDB(db.get(), app_root).ok());
+    EXPECT_TRUE(PutFileToDB(db.get(), folder).ok());
+    EXPECT_TRUE(PutFileToDB(db.get(), file).ok());
+  }
+
+  EXPECT_EQ(SYNC_STATUS_OK, InitializeMetadataDatabase());
+
+  base::FilePath path;
+  EXPECT_FALSE(metadata_database()->BuildPathForFile(sync_root.file_id(),
+                                                     &path));
+  EXPECT_TRUE(metadata_database()->BuildPathForFile(app_root.file_id(), &path));
+  EXPECT_EQ(base::FilePath(FPL("/")).NormalizePathSeparators(),
+            path);
+  EXPECT_TRUE(metadata_database()->BuildPathForFile(file.file_id(), &path));
+  EXPECT_EQ(base::FilePath(FPL("/folder/file")).NormalizePathSeparators(),
+            path);
+}
+
+TEST_F(MetadataDatabaseTest, UpdateByChangeListTest) {
+  DriveFileMetadata sync_root(CreateSyncRootMetadata());
+  DriveFileMetadata app_root(CreateAppRootMetadata(sync_root, "app_id"));
+  DriveFileMetadata disabled_app_root(
+      CreateAppRootMetadata(sync_root, "disabled_app"));
+  DriveFileMetadata file(CreateFileMetadata(app_root, "file"));
+  DriveFileMetadata renamed_file(CreateFileMetadata(app_root, "to be renamed"));
+  DriveFileMetadata folder(CreateFolderMetadata(app_root, "folder"));
+  DriveFileMetadata reorganized_file(
+      CreateFileMetadata(app_root, "to be reorganized"));
+  DriveFileMetadata updated_file(CreateFileMetadata(app_root, "to be updated"));
+  DriveFileMetadata noop_file(CreateFileMetadata(app_root, "have noop change"));
+  DriveFileMetadata new_file(CreateFileMetadata(app_root, "to be added later"));
+
+  {
+    scoped_ptr<leveldb::DB> db = InitializeLevelDB();
+    ASSERT_TRUE(db);
+
+    EXPECT_TRUE(PutFileToDB(db.get(), sync_root).ok());
+    EXPECT_TRUE(PutFileToDB(db.get(), app_root).ok());
+    EXPECT_TRUE(PutFileToDB(db.get(), disabled_app_root).ok());
+    EXPECT_TRUE(PutFileToDB(db.get(), file).ok());
+    EXPECT_TRUE(PutFileToDB(db.get(), renamed_file).ok());
+    EXPECT_TRUE(PutFileToDB(db.get(), folder).ok());
+    EXPECT_TRUE(PutFileToDB(db.get(), reorganized_file).ok());
+    EXPECT_TRUE(PutFileToDB(db.get(), updated_file).ok());
+    EXPECT_TRUE(PutFileToDB(db.get(), noop_file).ok());
+  }
+
+  EXPECT_EQ(SYNC_STATUS_OK, InitializeMetadataDatabase());
+
+  ApplyRenameChangeToMetadata("renamed", &renamed_file);
+  ApplyReorganizeChangeToMetadata(folder.file_id(), &reorganized_file);
+  ApplyContentChangeToMetadata(&updated_file);
+  ApplyNoopChangeToMetadata(&noop_file);
+  ApplyNewFileChangeToMetadata(&new_file);
+
+  ScopedVector<google_apis::ChangeResource> changes;
+  PushToChangeList(CreateChangeResourceFromMetadata(renamed_file), &changes);
+  PushToChangeList(CreateChangeResourceFromMetadata(
+      reorganized_file), &changes);
+  PushToChangeList(CreateChangeResourceFromMetadata(updated_file), &changes);
+  PushToChangeList(CreateChangeResourceFromMetadata(noop_file), &changes);
+  PushToChangeList(CreateChangeResourceFromMetadata(new_file), &changes);
+  EXPECT_EQ(SYNC_STATUS_OK, UpdateByChangeList(changes.Pass()));
+
+  VerifyFile(sync_root);
+  VerifyFile(app_root);
+  VerifyFile(disabled_app_root);
+  VerifyFile(file);
+  VerifyFile(renamed_file);
+  VerifyFile(folder);
+  VerifyFile(reorganized_file);
+  VerifyFile(updated_file);
+  VerifyFile(noop_file);
+  VerifyFile(new_file);
+  VerifyReloadConsistency();
+}
+
 }  // namespace drive_backend
 }  // namespace sync_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 ee6ebed..17bcca6 100644
--- a/chrome/browser/tab_contents/render_view_context_menu.cc
+++ b/chrome/browser/tab_contents/render_view_context_menu.cc
@@ -60,6 +60,7 @@
 #include "chrome/browser/ui/tab_contents/core_tab_helper.h"
 #include "chrome/common/chrome_constants.h"
 #include "chrome/common/chrome_switches.h"
+#include "chrome/common/content_restriction.h"
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/net/url_util.h"
 #include "chrome/common/pref_names.h"
@@ -78,7 +79,6 @@
 #include "content/public/browser/render_widget_host_view.h"
 #include "content/public/browser/user_metrics.h"
 #include "content/public/browser/web_contents.h"
-#include "content/public/common/content_restriction.h"
 #include "content/public/common/menu_item.h"
 #include "content/public/common/ssl_status.h"
 #include "content/public/common/url_utils.h"
@@ -1122,15 +1122,18 @@
       return observer->IsCommandIdEnabled(id);
   }
 
+  CoreTabHelper* core_tab_helper =
+      CoreTabHelper::FromWebContents(source_web_contents_);
+  int content_restrictions = 0;
+  if (core_tab_helper)
+    content_restrictions = core_tab_helper->content_restrictions();
   if (id == IDC_PRINT &&
-      (source_web_contents_->GetContentRestrictions() &
-          content::CONTENT_RESTRICTION_PRINT)) {
+      (content_restrictions & CONTENT_RESTRICTION_PRINT)) {
     return false;
   }
 
   if (id == IDC_SAVE_PAGE &&
-      (source_web_contents_->GetContentRestrictions() &
-          content::CONTENT_RESTRICTION_SAVE)) {
+      (content_restrictions & CONTENT_RESTRICTION_SAVE)) {
     return false;
   }
 
diff --git a/chrome/browser/tab_contents/tab_util.cc b/chrome/browser/tab_contents/tab_util.cc
index 9d82f22..fae1201 100644
--- a/chrome/browser/tab_contents/tab_util.cc
+++ b/chrome/browser/tab_contents/tab_util.cc
@@ -38,7 +38,7 @@
   if (ChromeWebUIControllerFactory::GetInstance()->UseWebUIForURL(
           profile, url) ||
       (service &&
-       service->extensions()->GetHostedAppByURL(ExtensionURLInfo(url)))) {
+       service->extensions()->GetHostedAppByURL(url))) {
     return SiteInstance::CreateForURL(profile, url);
   }
 
diff --git a/chrome/browser/task_manager/tab_contents_resource_provider.cc b/chrome/browser/task_manager/tab_contents_resource_provider.cc
index f4c1370..bce027d 100644
--- a/chrome/browser/task_manager/tab_contents_resource_provider.cc
+++ b/chrome/browser/task_manager/tab_contents_resource_provider.cc
@@ -13,6 +13,8 @@
 #include "chrome/browser/printing/background_printing_manager.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/search/instant_service.h"
+#include "chrome/browser/search/instant_service_factory.h"
 #include "chrome/browser/search/search.h"
 #include "chrome/browser/tab_contents/tab_util.h"
 #include "chrome/browser/task_manager/renderer_resource.h"
@@ -21,7 +23,6 @@
 #include "chrome/browser/task_manager/task_manager_util.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_finder.h"
-#include "chrome/browser/ui/browser_instant_controller.h"
 #include "chrome/browser/ui/browser_iterator.h"
 #include "chrome/browser/ui/tab_contents/tab_contents_iterator.h"
 #include "content/public/browser/notification_service.h"
@@ -207,14 +208,6 @@
   for (TabContentsIterator iterator; !iterator.done(); iterator.Next())
     Add(*iterator);
 
-  // Add all the Instant pages.
-  for (chrome::BrowserIterator it; !it.done(); it.Next()) {
-    if (it->instant_controller()) {
-      if (it->instant_controller()->instant()->GetNTPContents())
-        Add(it->instant_controller()->instant()->GetNTPContents());
-    }
-  }
-
   // Add all the prerender pages.
   std::vector<Profile*> profiles(
       g_browser_process->profile_manager()->GetLoadedProfiles());
@@ -229,6 +222,14 @@
     }
   }
 
+  // Add all the Instant Extended prerendered NTPs.
+  for (size_t i = 0; i < profiles.size(); ++i) {
+    const InstantService* instant_service =
+        InstantServiceFactory::GetForProfile(profiles[i]);
+    if (instant_service && instant_service->GetNTPContents())
+      Add(instant_service->GetNTPContents());
+  }
+
   // Add all the pages being background printed.
   printing::BackgroundPrintingManager* printing_manager =
       g_browser_process->background_printing_manager();
diff --git a/chrome/browser/task_manager/task_manager.cc b/chrome/browser/task_manager/task_manager.cc
index be9a3b9..8c5bae6 100644
--- a/chrome/browser/task_manager/task_manager.cc
+++ b/chrome/browser/task_manager/task_manager.cc
@@ -41,7 +41,7 @@
 #include "content/public/common/result_codes.h"
 #include "grit/generated_resources.h"
 #include "grit/ui_resources.h"
-#include "third_party/icu/public/i18n/unicode/coll.h"
+#include "third_party/icu/source/i18n/unicode/coll.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/base/text/bytes_formatting.h"
diff --git a/chrome/browser/translate/options_menu_model.cc b/chrome/browser/translate/options_menu_model.cc
index 0abea91..a6cd71b 100644
--- a/chrome/browser/translate/options_menu_model.cc
+++ b/chrome/browser/translate/options_menu_model.cc
@@ -6,7 +6,6 @@
 
 #include "base/metrics/histogram.h"
 #include "chrome/app/chrome_command_ids.h"
-#include "chrome/browser/infobars/infobar_service.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/translate/translate_infobar_delegate.h"
 #include "chrome/common/url_constants.h"
diff --git a/chrome/browser/translate/translate_infobar_delegate.cc b/chrome/browser/translate/translate_infobar_delegate.cc
index 20a5b0a..726be78 100644
--- a/chrome/browser/translate/translate_infobar_delegate.cc
+++ b/chrome/browser/translate/translate_infobar_delegate.cc
@@ -20,7 +20,7 @@
 #include "content/public/browser/web_contents.h"
 #include "grit/generated_resources.h"
 #include "grit/theme_resources.h"
-#include "third_party/icu/public/i18n/unicode/coll.h"
+#include "third_party/icu/source/i18n/unicode/coll.h"
 #include "ui/base/l10n/l10n_util.h"
 
 using content::NavigationEntry;
@@ -43,10 +43,14 @@
 
 // static
 void TranslateInfoBarDelegate::Create(
-    InfoBarService* infobar_service, bool replace_existing_infobar,
-    Type infobar_type, TranslateErrors::Type error_type, PrefService* prefs,
-    const ShortcutConfiguration& shortcut_config,
-    const std::string& original_language, const std::string& target_language) {
+    bool replace_existing_infobar,
+    InfoBarService* infobar_service,
+    Type infobar_type,
+    const std::string& original_language,
+    const std::string& target_language,
+    TranslateErrors::Type error_type,
+    PrefService* prefs,
+    const ShortcutConfiguration& shortcut_config) {
   // Check preconditions.
   if (infobar_type != TRANSLATION_ERROR) {
     DCHECK(TranslateManager::IsSupportedLanguage(target_language));
@@ -63,20 +67,22 @@
   TranslateInfoBarDelegate* old_delegate = NULL;
   for (size_t i = 0; i < infobar_service->infobar_count(); ++i) {
     old_delegate = infobar_service->infobar_at(i)->AsTranslateInfoBarDelegate();
-    if (old_delegate)
+    if (old_delegate) {
+      if (!replace_existing_infobar)
+        return;
       break;
+    }
   }
 
   // Create the new delegate.
   scoped_ptr<TranslateInfoBarDelegate> infobar(
-      new TranslateInfoBarDelegate(infobar_type, error_type, infobar_service,
-                                   prefs, shortcut_config,
-                                   original_language, target_language));
-  infobar->UpdateBackgroundAnimation(old_delegate);
+      new TranslateInfoBarDelegate(infobar_service, infobar_type, old_delegate,
+                                   original_language, target_language,
+                                   error_type, prefs, shortcut_config));
 
   // Do not create the after translate infobar if we are auto translating.
-  if (infobar_type == TranslateInfoBarDelegate::AFTER_TRANSLATE ||
-      infobar_type == TranslateInfoBarDelegate::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 ||
@@ -87,7 +93,8 @@
   // Add the new delegate if necessary.
   if (!old_delegate) {
     infobar_service->AddInfoBar(infobar.PassAs<InfoBarDelegate>());
-  } else if (replace_existing_infobar) {
+  } else {
+    DCHECK(replace_existing_infobar);
     infobar_service->ReplaceInfoBar(old_delegate,
                                     infobar.PassAs<InfoBarDelegate>());
   }
@@ -276,14 +283,6 @@
           shortcut_config_.always_translate_min_count);
 }
 
-void TranslateInfoBarDelegate::UpdateBackgroundAnimation(
-    TranslateInfoBarDelegate* previous_infobar) {
-  if (!previous_infobar || previous_infobar->IsError() == IsError())
-    background_animation_ = NONE;
-  else
-    background_animation_ = IsError() ? NORMAL_TO_ERROR : ERROR_TO_NORMAL;
-}
-
 // static
 string16 TranslateInfoBarDelegate::GetLanguageDisplayableName(
     const std::string& language_code) {
@@ -326,13 +325,14 @@
 }
 
 TranslateInfoBarDelegate::TranslateInfoBarDelegate(
-    Type infobar_type,
-    TranslateErrors::Type error_type,
     InfoBarService* infobar_service,
-    PrefService* prefs,
-    ShortcutConfiguration shortcut_config,
+    Type infobar_type,
+    TranslateInfoBarDelegate* old_delegate,
     const std::string& original_language,
-    const std::string& target_language)
+    const std::string& target_language,
+    TranslateErrors::Type error_type,
+    PrefService* prefs,
+    ShortcutConfiguration shortcut_config)
     : InfoBarDelegate(infobar_service),
       infobar_type_(infobar_type),
       background_animation_(NONE),
@@ -345,6 +345,9 @@
   DCHECK_NE((infobar_type_ == TRANSLATION_ERROR),
             (error_type_ == TranslateErrors::NONE));
 
+  if (old_delegate && (old_delegate->is_error() != is_error()))
+    background_animation_ = is_error() ? NORMAL_TO_ERROR : ERROR_TO_NORMAL;
+
   std::vector<std::string> language_codes;
   TranslateManager::GetSupportedLanguages(&language_codes);
 
@@ -384,16 +387,6 @@
   DCHECK_NE(kNoIndex, target_language_index_);
 }
 
-bool TranslateInfoBarDelegate::ShouldExpire(
-    const content::LoadCommittedDetails& details) const {
-  // Note: we allow closing this infobar even if the main frame navigation
-  // was programmatic and not initiated by the user - crbug.com/70261 .
-  if (!details.is_navigation_to_different_page() && !details.is_main_frame)
-    return false;
-
-  return InfoBarDelegate::ShouldExpireInternal(details);
-}
-
 void TranslateInfoBarDelegate::InfoBarDismissed() {
   if (infobar_type_ != BEFORE_TRANSLATE)
     return;
@@ -411,6 +404,16 @@
   return PAGE_ACTION_TYPE;
 }
 
+bool TranslateInfoBarDelegate::ShouldExpire(
+    const content::LoadCommittedDetails& details) const {
+  // Note: we allow closing this infobar even if the main frame navigation
+  // was programmatic and not initiated by the user - crbug.com/70261 .
+  if (!details.is_navigation_to_different_page() && !details.is_main_frame)
+    return false;
+
+  return InfoBarDelegate::ShouldExpireInternal(details);
+}
+
 TranslateInfoBarDelegate*
     TranslateInfoBarDelegate::AsTranslateInfoBarDelegate() {
   return this;
diff --git a/chrome/browser/translate/translate_infobar_delegate.h b/chrome/browser/translate/translate_infobar_delegate.h
index b934d32..5b21995 100644
--- a/chrome/browser/translate/translate_infobar_delegate.h
+++ b/chrome/browser/translate/translate_infobar_delegate.h
@@ -59,14 +59,14 @@
   // |infobar_service|, replacing any other translate infobar already present
   // there.  Otherwise, the infobar will only be added if there is no other
   // translate infobar already present.
-  static void Create(InfoBarService* infobar_service,
-                     bool replace_existing_infobar,
+  static void Create(bool replace_existing_infobar,
+                     InfoBarService* infobar_service,
                      Type infobar_type,
+                     const std::string& original_language,
+                     const std::string& target_language,
                      TranslateErrors::Type error_type,
                      PrefService* prefs,
-                     const ShortcutConfiguration& shortcut_config,
-                     const std::string& original_language,
-                     const std::string& target_language);
+                     const ShortcutConfiguration& shortcut_config);
 
   // Returns the number of languages supported.
   size_t num_languages() const { return languages_.size(); }
@@ -112,7 +112,7 @@
 
   // Returns true if the current infobar indicates an error (in which case it
   // should get a yellow background instead of a blue one).
-  bool IsError() const { return infobar_type_ == TRANSLATION_ERROR; }
+  bool is_error() const { return infobar_type_ == TRANSLATION_ERROR; }
 
   // Returns what kind of background fading effect the infobar should use when
   // its is shown.
@@ -157,11 +157,6 @@
   bool ShouldShowNeverTranslateShortcut();
   bool ShouldShowAlwaysTranslateShortcut();
 
-  // Sets this infobar background animation based on the previous infobar shown.
-  // A fading background effect is used when transitioning from a normal state
-  // to an error state (and vice-versa).
-  void UpdateBackgroundAnimation(TranslateInfoBarDelegate* previous_infobar);
-
   // Convenience method that returns the displayable language name for
   // |language_code| in the current application locale.
   static string16 GetLanguageDisplayableName(const std::string& language_code);
@@ -183,13 +178,14 @@
                                        bool autodetermined_source_language);
 
  protected:
-  TranslateInfoBarDelegate(Type infobar_type,
-                           TranslateErrors::Type error_type,
-                           InfoBarService* infobar_service,
-                           PrefService* prefs,
-                           ShortcutConfiguration shortcut_config,
+  TranslateInfoBarDelegate(InfoBarService* infobar_service,
+                           Type infobar_type,
+                           TranslateInfoBarDelegate* old_delegate,
                            const std::string& original_language,
-                           const std::string& target_language);
+                           const std::string& target_language,
+                           TranslateErrors::Type error_type,
+                           PrefService* prefs,
+                           ShortcutConfiguration shortcut_config);
 
  private:
   typedef std::pair<std::string, string16> LanguageNamePair;
diff --git a/chrome/browser/translate/translate_manager.cc b/chrome/browser/translate/translate_manager.cc
index 99fcf12..057084e 100644
--- a/chrome/browser/translate/translate_manager.cc
+++ b/chrome/browser/translate/translate_manager.cc
@@ -427,10 +427,9 @@
   TranslateBrowserMetrics::ReportInitiationStatus(
       TranslateBrowserMetrics::INITIATION_STATUS_SHOW_INFOBAR);
   TranslateInfoBarDelegate::Create(
-      InfoBarService::FromWebContents(web_contents), false,
-      TranslateInfoBarDelegate::BEFORE_TRANSLATE, TranslateErrors::NONE,
-      profile->GetPrefs(), ShortcutConfig(),
-      language_code, target_lang);
+      false, InfoBarService::FromWebContents(web_contents),
+      TranslateInfoBarDelegate::BEFORE_TRANSLATE, language_code, target_lang,
+      TranslateErrors::NONE, profile->GetPrefs(), ShortcutConfig());
 }
 
 void TranslateManager::InitiateTranslationPosted(int process_id,
@@ -474,22 +473,20 @@
     return;
   }
 
-  Profile* profile =
-      Profile::FromBrowserContext(web_contents->GetBrowserContext());
-
-  std::string source_lang(original_source_lang);
-
   // Translation can be kicked by context menu against unsupported languages.
   // Unsupported language strings should be replaced with
   // kUnknownLanguageCode in order to send a translation request with enabling
   // server side auto language detection.
+  std::string source_lang(original_source_lang);
   if (!IsSupportedLanguage(source_lang))
     source_lang = std::string(chrome::kUnknownLanguageCode);
 
+  Profile* profile =
+      Profile::FromBrowserContext(web_contents->GetBrowserContext());
   TranslateInfoBarDelegate::Create(
-      InfoBarService::FromWebContents(web_contents), true,
-      TranslateInfoBarDelegate::TRANSLATING, TranslateErrors::NONE,
-      profile->GetPrefs(), ShortcutConfig(), source_lang, target_lang);
+      true, InfoBarService::FromWebContents(web_contents),
+      TranslateInfoBarDelegate::TRANSLATING, source_lang, target_lang,
+      TranslateErrors::NONE, profile->GetPrefs(), ShortcutConfig());
 
   DCHECK(script_.get() != NULL);
 
@@ -604,18 +601,18 @@
   PrefService* prefs = Profile::FromBrowserContext(
       web_contents->GetBrowserContext())->GetPrefs();
   TranslateInfoBarDelegate::Create(
-      InfoBarService::FromWebContents(web_contents), true,
+      true, InfoBarService::FromWebContents(web_contents),
       (details->error_type == TranslateErrors::NONE) ?
-      TranslateInfoBarDelegate::AFTER_TRANSLATE :
-      TranslateInfoBarDelegate::TRANSLATION_ERROR,
-      details->error_type, prefs, ShortcutConfig(), details->source_language,
-      details->target_language);
+          TranslateInfoBarDelegate::AFTER_TRANSLATE :
+          TranslateInfoBarDelegate::TRANSLATION_ERROR,
+      details->source_language, details->target_language, details->error_type,
+      prefs, ShortcutConfig());
 
   if (details->error_type != TranslateErrors::NONE &&
       !web_contents->GetBrowserContext()->IsOffTheRecord()) {
     TranslateErrorDetails error_details;
     error_details.time = base::Time::Now();
-    error_details.url = web_contents->GetActiveURL();
+    error_details.url = web_contents->GetLastCommittedURL();
     error_details.error = details->error_type;
     NotifyTranslateError(error_details);
   }
@@ -670,14 +667,10 @@
       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);
+          true, InfoBarService::FromWebContents(web_contents),
+          TranslateInfoBarDelegate::TRANSLATION_ERROR, request.source_lang,
+          request.target_lang, TranslateErrors::NETWORK, profile->GetPrefs(),
+          ShortcutConfig());
 
       if (!web_contents->GetBrowserContext()->IsOffTheRecord()) {
         TranslateErrorDetails error_details;
@@ -720,8 +713,8 @@
 ShortcutConfiguration TranslateManager::ShortcutConfig() {
   ShortcutConfiguration config;
 
-  // The android implementation does not offer a drop down for space
-  // reason so we are more aggressive showing the shortcuts for never translate.
+  // The android implementation does not offer a drop down (for space reasons),
+  // so we are more aggressive about showing the shortcut to never translate.
   #if defined(OS_ANDROID)
   config.never_translate_min_count = 1;
   #else
diff --git a/chrome/browser/translate/translate_manager_browsertest.cc b/chrome/browser/translate/translate_manager_browsertest.cc
index ee3d7ff..7faeda1 100644
--- a/chrome/browser/translate/translate_manager_browsertest.cc
+++ b/chrome/browser/translate/translate_manager_browsertest.cc
@@ -51,7 +51,6 @@
 #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/cld/languages/public/languages.h"
 
 using content::NavigationController;
 using content::RenderViewHostTester;
@@ -509,7 +508,7 @@
   ASSERT_TRUE(infobar != NULL);
   EXPECT_EQ(TranslateInfoBarDelegate::TRANSLATION_ERROR,
             infobar->infobar_type());
-  EXPECT_TRUE(infobar->IsError());
+  EXPECT_TRUE(infobar->is_error());
   infobar->MessageInfoBarButtonPressed();
   SimulateTranslateScriptURLFetch(true);  // This time succeed.
 
@@ -560,69 +559,36 @@
   EXPECT_EQ(TranslateErrors::UNKNOWN_LANGUAGE, infobar->error_type());
 }
 
-// Tests that we show/don't show an info-bar for all languages the CLD can
-// report.
-TEST_F(TranslateManagerBrowserTest, TestAllLanguages) {
-  // The index in kExpectation are the Language enum (see languages.pb.h).
-  // true if we expect a translate infobar for that language.
-  // Note the supported languages are in translation_manager.cc, see
-  // kSupportedLanguages.
-  bool kExpectations[] = {
-    // 0-9
-    false, true, true, true, true, true, false, true, true, true,
-    // 10-19
-    false, true, true, true, true, true, true, true, true, true,
-    // 20-29
-    true, true, true, true, true, false, false, true, true, true,
-    // 30-39
-    true, true, false, true, true, true, true, false, true, false,
-    // 40-49
-    true, false, true, false, false, true, false, true, false, false,
-    // 50-59
-    false, false, false, true, true, true, true, false, false, false,
-    // 60-69
-    false, false, true, true, false, true, true, false, true, true,
-    // 70-79
-    false, false, false, false, false, false, false, true, false, false,
-    // 80-89
-    false, true, true, false, false, false, false, false, false, false,
-    // 90-99
-    false, true, false, false, false, false, false, false, false, false,
-    // 100-109
-    false, true, false, false, false, false, false, false, false, false,
-    // 110-119
-    false, false, false, false, false, false, false, false, false, false,
-    // 120-129
-    false, false, false, false, false, false, false, false, false, false,
-    // 130-139
-    false, false, false, false, false, false, false, false, false, true,
-    // 140-149
-    false, false, false, false, false, false, false, false, false, false,
-    // 150-159
-    false, false, false, false, false, false, false, false, false, false,
-    // 160
-    true
-  };
+// Tests that we show/don't show an info-bar for the languages.
+TEST_F(TranslateManagerBrowserTest, TestLanguages) {
+  std::vector<std::string> languages;
+  languages.push_back("en");
+  languages.push_back("ja");
+  languages.push_back("fr");
+  languages.push_back("ht");
+  languages.push_back("xx");
+  languages.push_back("zh");
+  languages.push_back("zh-CN");
+  languages.push_back("und");
 
   GURL url("http://www.google.com");
-  for (size_t i = 0; i < arraysize(kExpectations); ++i) {
-    ASSERT_LT(i, static_cast<size_t>(NUM_LANGUAGES));
-
-    std::string lang = LanguageCodeWithDialects(static_cast<Language>(i));
+  for (size_t i = 0; i < languages.size(); ++i) {
+    std::string lang = languages[i];
     SCOPED_TRACE(::testing::Message() << "Iteration " << i <<
-        " language=" << lang);
+                 " language=" << lang);
 
     // We should not have a translate infobar.
     TranslateInfoBarDelegate* infobar = GetTranslateInfoBar();
     ASSERT_TRUE(infobar == NULL);
 
     // Simulate navigating to a page.
-    NavigateAndCommit(url);
-    SimulateOnTranslateLanguageDetermined(lang, true);
+    SimulateNavigation(url, lang, true);
 
     // Verify we have/don't have an info-bar as expected.
     infobar = GetTranslateInfoBar();
-    EXPECT_EQ(kExpectations[i], infobar != NULL);
+    bool expected = TranslateManager::IsSupportedLanguage(lang) &&
+        lang != "en";
+    EXPECT_EQ(expected, infobar != NULL);
 
     // Close the info-bar if applicable.
     if (infobar != NULL)
diff --git a/chrome/browser/ui/android/tab_model/tab_model.cc b/chrome/browser/ui/android/tab_model/tab_model.cc
index 4840fde..d21b827 100644
--- a/chrome/browser/ui/android/tab_model/tab_model.cc
+++ b/chrome/browser/ui/android/tab_model/tab_model.cc
@@ -92,7 +92,7 @@
 }
 
 ToolbarModel::SecurityLevel TabModel::GetSecurityLevelForCurrentTab() {
-  return toolbar_model_->GetSecurityLevel();
+  return toolbar_model_->GetSecurityLevel(false);
 }
 
 string16 TabModel::GetSearchTermsForCurrentTab() {
diff --git a/chrome/browser/ui/app_list/app_list_controller_browsertest.cc b/chrome/browser/ui/app_list/app_list_controller_browsertest.cc
index 79c5594..6a7464e 100644
--- a/chrome/browser/ui/app_list/app_list_controller_browsertest.cc
+++ b/chrome/browser/ui/app_list/app_list_controller_browsertest.cc
@@ -42,7 +42,7 @@
 IN_PROC_BROWSER_TEST_F(AppListControllerBrowserTest, ShowAndDismiss) {
   AppListService* service = AppListService::Get();
   ASSERT_FALSE(service->IsAppListVisible());
-  service->ShowAppList(browser()->profile());
+  service->ShowForProfile(browser()->profile());
   ASSERT_TRUE(service->IsAppListVisible());
   service->DismissAppList();
   ASSERT_FALSE(service->IsAppListVisible());
@@ -60,10 +60,10 @@
 
   AppListService* service = AppListService::Get();
   ASSERT_FALSE(service->IsAppListVisible());
-  service->ShowAppList(browser()->profile());
+  service->ShowForProfile(browser()->profile());
   ASSERT_TRUE(service->IsAppListVisible());
   ASSERT_EQ(browser()->profile(), service->GetCurrentAppListProfile());
-  service->ShowAppList(profile2_);
+  service->ShowForProfile(profile2_);
   ASSERT_TRUE(service->IsAppListVisible());
   ASSERT_EQ(profile2_, service->GetCurrentAppListProfile());
   service->DismissAppList();
diff --git a/chrome/browser/ui/app_list/app_list_service.h b/chrome/browser/ui/app_list/app_list_service.h
index ebb8f68..edac211 100644
--- a/chrome/browser/ui/app_list/app_list_service.h
+++ b/chrome/browser/ui/app_list/app_list_service.h
@@ -34,23 +34,27 @@
 
   static void RegisterPrefs(PrefRegistrySimple* registry);
 
-  virtual base::FilePath GetProfilePath(
-      const base::FilePath& user_data_dir) = 0;
-
   static void RecordShowTimings(const CommandLine& command_line);
 
-  // Show the app list.
-  virtual void ShowAppList(Profile* requested_profile) = 0;
+  // Perform Chrome first run logic. This is executed before Chrome's threads
+  // have been created.
+  virtual void HandleFirstRun() = 0;
 
-  // Dismiss the app list.
-  virtual void DismissAppList() = 0;
-
-  // TODO(koz): Merge this into ShowAppList().
-  virtual void SetAppListProfile(const base::FilePath& profile_file_path) = 0;
+  virtual base::FilePath GetProfilePath(
+      const base::FilePath& user_data_dir) = 0;
+  virtual void SetProfilePath(const base::FilePath& profile_path) = 0;
 
   // Show the app list for the profile configured in the user data dir for the
   // current browser process.
-  virtual void ShowForSavedProfile() = 0;
+  virtual void Show() = 0;
+
+  // Show the app list for the given profile. If it differs from the profile the
+  // app list is currently showing, repopulate the app list and save the new
+  // profile to local prefs as the default app list profile.
+  virtual void ShowForProfile(Profile* requested_profile) = 0;
+
+  // Dismiss the app list.
+  virtual void DismissAppList() = 0;
 
   // Get the profile the app list is currently showing.
   virtual Profile* GetCurrentAppListProfile() = 0;
diff --git a/chrome/browser/ui/app_list/app_list_service_disabled.cc b/chrome/browser/ui/app_list/app_list_service_disabled.cc
index 5b46a16..6c1ec63 100644
--- a/chrome/browser/ui/app_list/app_list_service_disabled.cc
+++ b/chrome/browser/ui/app_list/app_list_service_disabled.cc
@@ -21,20 +21,19 @@
   AppListServiceDisabled() {}
 
   // AppListService overrides:
+  virtual void HandleFirstRun() OVERRIDE {}
   virtual void Init(Profile* initial_profile) OVERRIDE {}
 
   virtual base::FilePath GetProfilePath(
       const base::FilePath& user_data_dir) OVERRIDE {
     return base::FilePath();
   }
+  virtual void SetProfilePath(const base::FilePath& profile_path) OVERRIDE {}
 
-  virtual void ShowForSavedProfile() OVERRIDE {}
-  virtual void ShowAppList(Profile* profile) OVERRIDE {}
+  virtual void Show() OVERRIDE {}
+  virtual void ShowForProfile(Profile* profile) OVERRIDE {}
   virtual void DismissAppList() OVERRIDE {}
 
-  virtual void SetAppListProfile(
-    const base::FilePath& profile_file_path) OVERRIDE {}
-
   virtual Profile* GetCurrentAppListProfile() OVERRIDE { return NULL; }
   virtual bool IsAppListVisible() const OVERRIDE { return false; }
   virtual void EnableAppList(Profile* initial_profile) OVERRIDE {}
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 0dcee73..8054e87 100644
--- a/chrome/browser/ui/app_list/app_list_service_impl.cc
+++ b/chrome/browser/ui/app_list/app_list_service_impl.cc
@@ -4,6 +4,8 @@
 
 #include "chrome/browser/ui/app_list/app_list_service_impl.h"
 
+#include "apps/pref_names.h"
+#include "base/command_line.h"
 #include "base/metrics/histogram.h"
 #include "base/prefs/pref_service.h"
 #include "base/time/time.h"
@@ -11,6 +13,7 @@
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/common/chrome_constants.h"
+#include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/notification_details.h"
@@ -66,6 +69,11 @@
   }
 }
 
+void SetAppListEnabledPreference(bool enabled) {
+  PrefService* local_state = g_browser_process->local_state();
+  local_state->SetBoolean(apps::prefs::kAppLauncherHasBeenEnabled, enabled);
+}
+
 }  // namespace
 
 // static
@@ -107,6 +115,8 @@
 
 AppListServiceImpl::~AppListServiceImpl() {}
 
+void AppListServiceImpl::HandleFirstRun() {}
+
 void AppListServiceImpl::Init(Profile* initial_profile) {}
 
 base::FilePath AppListServiceImpl::GetProfilePath(
@@ -121,20 +131,28 @@
   // If the user has no profile preference for the app launcher, default to the
   // last browser profile used.
   if (app_list_profile.empty() &&
-      local_state->HasPrefPath(prefs::kProfileLastUsed))
+      local_state->HasPrefPath(prefs::kProfileLastUsed)) {
     app_list_profile = local_state->GetString(prefs::kProfileLastUsed);
+  }
 
-  std::string profile_path = app_list_profile.empty() ?
-      chrome::kInitialProfile :
-      app_list_profile;
+  // If there is no last used profile recorded, use the initial profile.
+  if (app_list_profile.empty())
+    app_list_profile = chrome::kInitialProfile;
 
-  return user_data_dir.AppendASCII(profile_path);
+  return user_data_dir.AppendASCII(app_list_profile);
+}
+
+void AppListServiceImpl::SetProfilePath(const base::FilePath& profile_path) {
+  g_browser_process->local_state()->SetString(
+      prefs::kAppListProfile,
+      profile_path.BaseName().MaybeAsASCII());
 }
 
 AppListControllerDelegate* AppListServiceImpl::CreateControllerDelegate() {
   return NULL;
 }
 
+void AppListServiceImpl::CreateShortcut() {}
 void AppListServiceImpl::OnSigninStatusChanged() {}
 
 // We need to watch for profile removal to keep kAppListProfile updated.
@@ -158,16 +176,17 @@
   OnSigninStatusChanged();
 }
 
-void AppListServiceImpl::SetAppListProfile(
-    const base::FilePath& profile_file_path) {
+void AppListServiceImpl::Show() {
   profile_loader_.LoadProfileInvalidatingOtherLoads(
-      profile_file_path, base::Bind(&AppListServiceImpl::ShowAppList,
-                                    weak_factory_.GetWeakPtr()));
+      GetProfilePath(g_browser_process->profile_manager()->user_data_dir()),
+      base::Bind(&AppListServiceImpl::ShowForProfile,
+                 weak_factory_.GetWeakPtr()));
 }
 
-void AppListServiceImpl::ShowForSavedProfile() {
-  SetAppListProfile(GetProfilePath(
-      g_browser_process->profile_manager()->user_data_dir()));
+void AppListServiceImpl::EnableAppList(Profile* initial_profile) {
+  SetAppListEnabledPreference(true);
+  SetProfilePath(initial_profile->GetPath());
+  CreateShortcut();
 }
 
 Profile* AppListServiceImpl::GetCurrentAppListProfile() {
@@ -192,9 +211,10 @@
   profile_loader_.InvalidatePendingProfileLoads();
 }
 
-void AppListServiceImpl::SaveProfilePathToLocalState(
-    const base::FilePath& profile_file_path) {
-  g_browser_process->local_state()->SetString(
-      prefs::kAppListProfile,
-      profile_file_path.BaseName().MaybeAsASCII());
+void AppListServiceImpl::HandleCommandLineFlags(Profile* initial_profile) {
+  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableAppList))
+    EnableAppList(initial_profile);
+
+  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableAppList))
+    SetAppListEnabledPreference(false);
 }
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 01cace7..5f7d70f 100644
--- a/chrome/browser/ui/app_list/app_list_service_impl.h
+++ b/chrome/browser/ui/app_list/app_list_service_impl.h
@@ -46,18 +46,26 @@
   ProfileLoader& profile_loader() { return profile_loader_; }
   const ProfileLoader& profile_loader() const { return profile_loader_; }
 
-  // Save |profile_file_path| as the app list profile in local state.
-  void SaveProfilePathToLocalState(const base::FilePath& profile_file_path);
+  // Process command line flags shared between desktop implementations of the
+  // app list. Currently this allows for enabling or disabling the app list.
+  void HandleCommandLineFlags(Profile* initial_profile);
+
+  // Create a platform-specific shortcut for the app list.
+  virtual void CreateShortcut();
 
   // Called in response to observed successful and unsuccessful signin changes.
   virtual void OnSigninStatusChanged();
 
   // AppListService overrides:
+  virtual void HandleFirstRun() OVERRIDE;
   virtual void Init(Profile* initial_profile) OVERRIDE;
+
+  // Returns the app list path configured in BrowserProcess::local_state().
   virtual base::FilePath GetProfilePath(
       const base::FilePath& user_data_dir) OVERRIDE;
-
-  virtual void ShowForSavedProfile() OVERRIDE;
+  virtual void SetProfilePath(const base::FilePath& profile_path) OVERRIDE;
+  virtual void Show() OVERRIDE;
+  virtual void EnableAppList(Profile* initial_profile) OVERRIDE;
   virtual AppListControllerDelegate* CreateControllerDelegate() OVERRIDE;
 
  private:
@@ -69,12 +77,6 @@
                        Profile* profile,
                        Profile::CreateStatus status);
 
-  // AppListService overrides:
-  // Update the profile path stored in local prefs, load it (if not already
-  // loaded), and show the app list.
-  virtual void SetAppListProfile(
-      const base::FilePath& profile_file_path) OVERRIDE;
-
   virtual Profile* GetCurrentAppListProfile() OVERRIDE;
 
   // ProfileInfoCacheObserver overrides:
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 7012d2d..bf64460 100644
--- a/chrome/browser/ui/app_list/app_list_service_mac.mm
+++ b/chrome/browser/ui/app_list/app_list_service_mac.mm
@@ -5,6 +5,7 @@
 #include <ApplicationServices/ApplicationServices.h>
 #import <Cocoa/Cocoa.h>
 
+#include "apps/app_launcher.h"
 #include "apps/app_shim/app_shim_handler_mac.h"
 #include "base/bind.h"
 #include "base/command_line.h"
@@ -14,8 +15,10 @@
 #include "base/memory/singleton.h"
 #include "base/message_loop/message_loop.h"
 #include "base/observer_list.h"
+#include "chrome/browser/browser_process.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/extension_system.h"
+#include "chrome/browser/profiles/profile_manager.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"
@@ -60,13 +63,13 @@
 
   // AppListService overrides:
   virtual void Init(Profile* initial_profile) OVERRIDE;
-  virtual void ShowAppList(Profile* requested_profile) OVERRIDE;
+  virtual void ShowForProfile(Profile* requested_profile) OVERRIDE;
   virtual void DismissAppList() OVERRIDE;
   virtual bool IsAppListVisible() const OVERRIDE;
-  virtual void EnableAppList(Profile* initial_profile) OVERRIDE;
   virtual gfx::NativeWindow GetAppListWindow() OVERRIDE;
 
-  // AppListServiceImpl override:
+  // AppListServiceImpl overrides:
+  virtual void CreateShortcut() OVERRIDE;
   virtual void OnSigninStatusChanged() OVERRIDE;
 
   // AppShimHandler overrides:
@@ -85,6 +88,7 @@
   AppListServiceMac() {}
 
   base::scoped_nsobject<AppListWindowController> window_controller_;
+  base::scoped_nsobject<NSRunningApplication> previously_active_application_;
 
   // 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
@@ -174,7 +178,7 @@
 }
 
 // Check that there is an app list shim. If enabling and there is not, make one.
-// If disabling with --enable-app-list-shim=0, and there is one, delete it.
+// If the flag is not present, and there is a shim, delete it.
 void CheckAppListShimOnFileThread(const base::FilePath& profile_path) {
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
   const bool enable =
@@ -203,6 +207,21 @@
                            web_app::ALLOW_DUPLICATE_SHORTCUTS);
 }
 
+NSRunningApplication* ActiveApplicationNotChrome() {
+  NSArray* applications = [[NSWorkspace sharedWorkspace] runningApplications];
+  for (NSRunningApplication* application in applications) {
+    if (![application isActive])
+      continue;
+
+    if ([application isEqual:[NSRunningApplication currentApplication]])
+      return nil;  // Chrome is active.
+
+    return application;
+  }
+
+  return nil;
+}
+
 AppListControllerDelegateCocoa::AppListControllerDelegateCocoa() {}
 
 AppListControllerDelegateCocoa::~AppListControllerDelegateCocoa() {}
@@ -270,10 +289,12 @@
   // browser window open and a new window is opened, and during process startup
   // to handle the silent launch case (e.g. for app shims). In the startup case,
   // a profile has not yet been determined so |initial_profile| will be NULL.
-  if (initial_profile) {
-    static bool checked_shim = false;
-    if (!checked_shim) {
-      checked_shim = true;
+  static bool init_called_with_profile = false;
+  if (initial_profile && !init_called_with_profile) {
+    init_called_with_profile = true;
+    HandleCommandLineFlags(initial_profile);
+    if (!apps::IsAppLauncherEnabled()) {
+      // Not yet enabled via the Web Store. Check for the chrome://flag.
       content::BrowserThread::PostTask(
           content::BrowserThread::FILE, FROM_HERE,
           base::Bind(&CheckAppListShimOnFileThread,
@@ -290,7 +311,7 @@
                                         AppListServiceMac::GetInstance());
 }
 
-void AppListServiceMac::ShowAppList(Profile* requested_profile) {
+void AppListServiceMac::ShowForProfile(Profile* requested_profile) {
   InvalidatePendingProfileLoads();
 
   if (IsAppListVisible() && (requested_profile == profile())) {
@@ -298,7 +319,7 @@
     return;
   }
 
-  SaveProfilePathToLocalState(requested_profile->GetPath());
+  SetProfilePath(requested_profile->GetPath());
 
   DismissAppList();
   CreateAppList(requested_profile);
@@ -309,6 +330,22 @@
   if (!IsAppListVisible())
     return;
 
+  // If the app list is currently the main window, it will activate the next
+  // Chrome window when dismissed. But if a different application was active
+  // when the app list was shown, activate that instead.
+  base::scoped_nsobject<NSRunningApplication> prior_app;
+  if ([[window_controller_ window] isMainWindow])
+    prior_app.swap(previously_active_application_);
+  else
+    previously_active_application_.reset();
+
+  // If activation is successful, the app list will lose main status and try to
+  // close itself again. It can't be closed in this runloop iteration without
+  // OSX deciding to raise the next Chrome window, and _then_ activating the
+  // application on top. This also occurs if no activation option is given.
+  if ([prior_app activateWithOptions:NSApplicationActivateIgnoringOtherApps])
+    return;
+
   [[window_controller_ window] close];
 
   FOR_EACH_OBSERVER(apps::AppShimHandler::Host,
@@ -320,8 +357,9 @@
   return [[window_controller_ window] isVisible];
 }
 
-void AppListServiceMac::EnableAppList(Profile* initial_profile) {
-  // TODO(tapted): Implement enable logic here for OSX.
+void AppListServiceMac::CreateShortcut() {
+  CreateAppListShim(GetProfilePath(
+      g_browser_process->profile_manager()->user_data_dir()));
 }
 
 NSWindow* AppListServiceMac::GetAppListWindow() {
@@ -334,7 +372,7 @@
 
 void AppListServiceMac::OnShimLaunch(apps::AppShimHandler::Host* host,
                                      apps::AppShimLaunchType launch_type) {
-  ShowForSavedProfile();
+  Show();
   observers_.AddObserver(host);
   host->OnAppLaunchComplete(apps::APP_SHIM_LAUNCH_SUCCESS);
 }
@@ -457,6 +495,11 @@
   NSWindow* window = GetAppListWindow();
   DCHECK(window);
   [window setFrameOrigin:GetAppListWindowOrigin(window)];
+
+  // Before activating, see if an application other than Chrome is currently the
+  // active application, so that it can be reactivated when dismissing.
+  previously_active_application_.reset([ActiveApplicationNotChrome() retain]);
+
   [window makeKeyAndOrderFront:nil];
   [NSApp activateIgnoringOtherApps:YES];
 }
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 8e96c70..15a5ae9 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
@@ -78,7 +78,7 @@
   EXPECT_EQ(0, close_count_);
 
   // With no saved profile, the default profile should be chosen and saved.
-  service->ShowForSavedProfile();
+  service->Show();
   EXPECT_EQ(browser()->profile(), service->GetCurrentAppListProfile());
   EXPECT_TRUE(service->IsAppListVisible());
   EXPECT_EQ(0, launch_count_);
@@ -118,7 +118,7 @@
 
   // Verify that observers are correctly removed by ensuring that |close_count_|
   // is unchanged when the app list is dismissed again.
-  service->ShowAppList(browser()->profile());
+  service->ShowForProfile(browser()->profile());
   EXPECT_TRUE(service->IsAppListVisible());
   EXPECT_EQ(3, launch_count_);
   service->DismissAppList();
diff --git a/chrome/browser/ui/app_list/search/term_break_iterator.cc b/chrome/browser/ui/app_list/search/term_break_iterator.cc
index 071a552..1349683 100644
--- a/chrome/browser/ui/app_list/search/term_break_iterator.cc
+++ b/chrome/browser/ui/app_list/search/term_break_iterator.cc
@@ -7,7 +7,7 @@
 #include "base/i18n/char_iterator.h"
 #include "base/logging.h"
 #include "base/strings/string_util.h"
-#include "third_party/icu/public/common/unicode/uchar.h"
+#include "third_party/icu/source/common/unicode/uchar.h"
 
 namespace app_list {
 
diff --git a/chrome/browser/ui/app_list/search/tokenized_string_char_iterator.cc b/chrome/browser/ui/app_list/search/tokenized_string_char_iterator.cc
index 5a122b6..6999edd 100644
--- a/chrome/browser/ui/app_list/search/tokenized_string_char_iterator.cc
+++ b/chrome/browser/ui/app_list/search/tokenized_string_char_iterator.cc
@@ -6,7 +6,7 @@
 
 #include "base/i18n/char_iterator.h"
 #include "base/logging.h"
-#include "third_party/icu/public/common/unicode/utf16.h"
+#include "third_party/icu/source/common/unicode/utf16.h"
 
 namespace app_list {
 
diff --git a/chrome/browser/ui/app_modal_dialogs/javascript_dialog_manager.cc b/chrome/browser/ui/app_modal_dialogs/javascript_dialog_manager.cc
index fc3cc46..965281b 100644
--- a/chrome/browser/ui/app_modal_dialogs/javascript_dialog_manager.cc
+++ b/chrome/browser/ui/app_modal_dialogs/javascript_dialog_manager.cc
@@ -251,7 +251,7 @@
   if (extension_host_) {
     const extensions::Extension* extension = extension_host_->
       profile()->GetExtensionService()->extensions()->
-      GetExtensionOrAppByURL(ExtensionURLInfo(origin_url));
+      GetExtensionOrAppByURL(origin_url);
     if (extension) {
       return UTF8ToUTF16(base::StringPiece(extension->name()));
     }
diff --git a/chrome/browser/ui/ash/app_list/app_list_service_ash.cc b/chrome/browser/ui/ash/app_list/app_list_service_ash.cc
index 4303770..cf10ee6 100644
--- a/chrome/browser/ui/ash/app_list/app_list_service_ash.cc
+++ b/chrome/browser/ui/ash/app_list/app_list_service_ash.cc
@@ -28,7 +28,7 @@
   // AppListService overrides:
   virtual base::FilePath GetProfilePath(
       const base::FilePath& user_data_dir) OVERRIDE;
-  virtual void ShowAppList(Profile* default_profile) OVERRIDE;
+  virtual void ShowForProfile(Profile* default_profile) OVERRIDE;
   virtual bool IsAppListVisible() const OVERRIDE;
   virtual void DismissAppList() OVERRIDE;
   virtual void EnableAppList(Profile* initial_profile) OVERRIDE;
@@ -42,7 +42,7 @@
   return ChromeLauncherController::instance()->profile()->GetPath();
 }
 
-void AppListServiceAsh::ShowAppList(Profile* default_profile) {
+void AppListServiceAsh::ShowForProfile(Profile* default_profile) {
   // This may not work correctly if the profile passed in is different from the
   // one the ash Shell is currently using.
   // TODO(ananta): Handle profile changes correctly when !defined(OS_CHROMEOS).
diff --git a/chrome/browser/ui/auto_login_infobar_delegate.h b/chrome/browser/ui/auto_login_infobar_delegate.h
index 96bebb7..6b2366b 100644
--- a/chrome/browser/ui/auto_login_infobar_delegate.h
+++ b/chrome/browser/ui/auto_login_infobar_delegate.h
@@ -32,16 +32,13 @@
     std::string username;
   };
 
-  // Creates an autologin delegate and adds it to |infobar_service|.
+  // Creates an autologin infobar delegate and adds it to |infobar_service|.
   static void Create(InfoBarService* infobar_service, const Params& params);
 
  protected:
   AutoLoginInfoBarDelegate(InfoBarService* owner, const Params& params);
   virtual ~AutoLoginInfoBarDelegate();
 
-  // ConfirmInfoBarDelegate:
-  virtual string16 GetMessageText() const OVERRIDE;
-
  private:
   // Enum values used for UMA histograms.
   enum Actions {
@@ -59,6 +56,7 @@
   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/autofill/autofill_dialog_controller.h b/chrome/browser/ui/autofill/autofill_dialog_controller.h
index 7662b81..8079a02 100644
--- a/chrome/browser/ui/autofill/autofill_dialog_controller.h
+++ b/chrome/browser/ui/autofill/autofill_dialog_controller.h
@@ -194,12 +194,14 @@
   // A button in the dialog's overlay has been pressed.
   virtual void OverlayButtonPressed() = 0;
 
-  // Called when the view has been cancelled.
-  virtual void OnCancel() = 0;
+  // Called when the view has been cancelled. Returns true if the dialog should
+  // now close, or false to keep it open.
+  virtual bool OnCancel() = 0;
 
   // Called when the view has been accepted. This could be to submit the payment
-  // info or to handle a required action.
-  virtual void OnAccept() = 0;
+  // info or to handle a required action. Returns true if the dialog should now
+  // close, or false to keep it open.
+  virtual bool OnAccept() = 0;
 
   // Returns the profile for this dialog.
   virtual Profile* profile() = 0;
diff --git a/chrome/browser/ui/autofill/autofill_dialog_controller_browsertest.cc b/chrome/browser/ui/autofill/autofill_dialog_controller_browsertest.cc
index 60e75c4..916fe15 100644
--- a/chrome/browser/ui/autofill/autofill_dialog_controller_browsertest.cc
+++ b/chrome/browser/ui/autofill/autofill_dialog_controller_browsertest.cc
@@ -508,6 +508,8 @@
   EXPECT_FALSE(controller()->ShouldShowDetailArea());
   EXPECT_FALSE(controller()->CurrentAutocheckoutSteps().empty());
   EXPECT_TRUE(controller()->ShouldShowProgressBar());
+  controller()->GetTestableView()->CancelForTesting();
+  RunMessageLoop();
 }
 
 #if defined(OS_MACOSX)
diff --git a/chrome/browser/ui/autofill/autofill_dialog_controller_impl.cc b/chrome/browser/ui/autofill/autofill_dialog_controller_impl.cc
index 6ed07ec..a5e4030 100644
--- a/chrome/browser/ui/autofill/autofill_dialog_controller_impl.cc
+++ b/chrome/browser/ui/autofill/autofill_dialog_controller_impl.cc
@@ -34,6 +34,7 @@
 #include "chrome/browser/ui/extensions/native_app_window.h"
 #include "chrome/common/chrome_version_info.h"
 #include "chrome/common/pref_names.h"
+#include "chrome/common/render_messages.h"
 #include "chrome/common/url_constants.h"
 #include "components/autofill/content/browser/risk/fingerprint.h"
 #include "components/autofill/content/browser/risk/proto/fingerprint.pb.h"
@@ -60,6 +61,7 @@
 #include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/notification_service.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_view.h"
 #include "content/public/common/url_constants.h"
@@ -68,6 +70,7 @@
 #include "grit/generated_resources.h"
 #include "grit/theme_resources.h"
 #include "grit/webkit_resources.h"
+#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
 #include "net/cert/cert_status_flags.h"
 #include "ui/base/base_window.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -375,20 +378,39 @@
       return l10n_util::GetStringUTF16(IDS_AUTOFILL_WALLET_BUYER_ACCOUNT_ERROR);
 
     case wallet::WalletClient::BAD_REQUEST:
+      return l10n_util::GetStringFUTF16(
+          IDS_AUTOFILL_WALLET_UPGRADE_CHROME_ERROR,
+          ASCIIToUTF16("71"));
+
     case wallet::WalletClient::INVALID_PARAMS:
+      return l10n_util::GetStringFUTF16(
+          IDS_AUTOFILL_WALLET_UPGRADE_CHROME_ERROR,
+          ASCIIToUTF16("42"));
+
     case wallet::WalletClient::UNSUPPORTED_API_VERSION:
-      return l10n_util::GetStringUTF16(
-          IDS_AUTOFILL_WALLET_UPGRADE_CHROME_ERROR);
+      return l10n_util::GetStringFUTF16(
+          IDS_AUTOFILL_WALLET_UPGRADE_CHROME_ERROR,
+          ASCIIToUTF16("43"));
 
     case wallet::WalletClient::SERVICE_UNAVAILABLE:
       return l10n_util::GetStringUTF16(
           IDS_AUTOFILL_WALLET_SERVICE_UNAVAILABLE_ERROR);
 
     case wallet::WalletClient::INTERNAL_ERROR:
+      return l10n_util::GetStringFUTF16(IDS_AUTOFILL_WALLET_UNKNOWN_ERROR,
+                                        ASCIIToUTF16("62"));
+
     case wallet::WalletClient::MALFORMED_RESPONSE:
+      return l10n_util::GetStringFUTF16(IDS_AUTOFILL_WALLET_UNKNOWN_ERROR,
+                                        ASCIIToUTF16("72"));
+
     case wallet::WalletClient::NETWORK_ERROR:
+      return l10n_util::GetStringFUTF16(IDS_AUTOFILL_WALLET_UNKNOWN_ERROR,
+                                        ASCIIToUTF16("73"));
+
     case wallet::WalletClient::UNKNOWN_ERROR:
-      return l10n_util::GetStringUTF16(IDS_AUTOFILL_WALLET_UNKNOWN_ERROR);
+      return l10n_util::GetStringFUTF16(IDS_AUTOFILL_WALLET_UNKNOWN_ERROR,
+                                        ASCIIToUTF16("74"));
   }
 
   NOTREACHED();
@@ -432,6 +454,12 @@
 
   GetMetricLogger().LogDialogInitialUserState(
       GetDialogType(), initial_user_state_);
+
+  if (deemphasized_render_view_) {
+    web_contents()->GetRenderViewHost()->Send(
+        new ChromeViewMsg_SetVisuallyDeemphasized(
+            web_contents()->GetRenderViewHost()->GetRoutingID(), false));
+  }
 }
 
 // static
@@ -615,10 +643,6 @@
     view_->Hide();
 }
 
-bool AutofillDialogControllerImpl::AutocheckoutIsRunning() const {
-  return autocheckout_state_ == AUTOCHECKOUT_IN_PROGRESS;
-}
-
 void AutofillDialogControllerImpl::OnAutocheckoutError() {
   DCHECK_EQ(AUTOCHECKOUT_IN_PROGRESS, autocheckout_state_);
   GetMetricLogger().LogAutocheckoutDuration(
@@ -691,14 +715,15 @@
 }
 
 string16 AutofillDialogControllerImpl::CancelButtonText() const {
-  if (autocheckout_state_ == AUTOCHECKOUT_ERROR)
-    return l10n_util::GetStringUTF16(IDS_OK);
-  if (autocheckout_state_ == AUTOCHECKOUT_SUCCESS)
-    return l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_CONTINUE_BUTTON);
   return l10n_util::GetStringUTF16(IDS_CANCEL);
 }
 
 string16 AutofillDialogControllerImpl::ConfirmButtonText() const {
+  if (autocheckout_state_ == AUTOCHECKOUT_ERROR)
+    return l10n_util::GetStringUTF16(IDS_OK);
+  if (autocheckout_state_ == AUTOCHECKOUT_SUCCESS)
+    return l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_CONTINUE_BUTTON);
+
   return l10n_util::GetStringUTF16(IsSubmitPausedOn(wallet::VERIFY_CVV) ?
       IDS_AUTOFILL_DIALOG_VERIFY_BUTTON : IDS_AUTOFILL_DIALOG_SUBMIT_BUTTON);
 }
@@ -762,9 +787,11 @@
 }
 
 int AutofillDialogControllerImpl::GetDialogButtons() const {
-  if (autocheckout_state_ != AUTOCHECKOUT_NOT_STARTED)
+  if (autocheckout_state_ == AUTOCHECKOUT_IN_PROGRESS)
     return ui::DIALOG_BUTTON_CANCEL;
-  return ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL;
+  if (autocheckout_state_ == AUTOCHECKOUT_NOT_STARTED)
+    return ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL;
+  return ui::DIALOG_BUTTON_OK;
 }
 
 bool AutofillDialogControllerImpl::IsDialogButtonEnabled(
@@ -772,14 +799,20 @@
   if (button == ui::DIALOG_BUTTON_OK) {
     if (IsSubmitPausedOn(wallet::VERIFY_CVV))
       return true;
-    if (is_submitting_ || ShouldShowSpinner())
+
+    if (ShouldShowSpinner())
       return false;
+
+    if (is_submitting_) {
+      return autocheckout_state_ == AUTOCHECKOUT_SUCCESS ||
+             autocheckout_state_ == AUTOCHECKOUT_ERROR;
+    }
+
     return true;
   }
 
   DCHECK_EQ(ui::DIALOG_BUTTON_CANCEL, button);
-  return !is_submitting_ || autocheckout_state_ != AUTOCHECKOUT_NOT_STARTED ||
-         IsSubmitPausedOn(wallet::VERIFY_CVV);
+  return !is_submitting_ || IsSubmitPausedOn(wallet::VERIFY_CVV);
 }
 
 DialogOverlayState AutofillDialogControllerImpl::GetDialogOverlay() const {
@@ -808,16 +841,16 @@
         cc_number.substr(cc_number.size() - 4));
     string.text = l10n_util::GetStringUTF16(
         IDS_AUTOFILL_DIALOG_CARD_GENERATION_DONE);
-    // TODO(estade): figure out correct color.
-    string.text_color = SK_ColorGRAY;
+    string.text_color = SK_ColorBLACK;
+    string.alignment = gfx::ALIGN_CENTER;
 
     state.strings.push_back(DialogOverlayString());
     DialogOverlayString& subtext = state.strings.back();
     subtext.font = rb.GetFont(ui::ResourceBundle::BaseFont);
-    // TODO(estade): figure out correct color.
-    subtext.text_color = SK_ColorGRAY;
+    subtext.text_color = SkColorSetRGB(102, 102, 102);
     subtext.text = l10n_util::GetStringUTF16(
         IDS_AUTOFILL_DIALOG_CARD_GENERATION_EXPLANATION);
+    subtext.alignment = gfx::ALIGN_CENTER;
 
     state.button_text = l10n_util::GetStringUTF16(
         IDS_AUTOFILL_DIALOG_CARD_GENERATION_OK_BUTTON);
@@ -829,8 +862,7 @@
     // "Submitting" waiting page.
     string.text = l10n_util::GetStringUTF16(
         IDS_AUTOFILL_DIALOG_CARD_GENERATION_IN_PROGRESS);
-    // TODO(estade): figure out correct color.
-    string.text_color = SK_ColorGRAY;
+    string.text_color = SK_ColorBLACK;
     string.alignment = gfx::ALIGN_CENTER;
   }
 
@@ -1898,7 +1930,7 @@
   FinishSubmit();
 }
 
-void AutofillDialogControllerImpl::OnCancel() {
+bool AutofillDialogControllerImpl::OnCancel() {
   HidePopup();
   if (autocheckout_state_ == AUTOCHECKOUT_NOT_STARTED && !is_submitting_)
     LogOnCancelMetrics();
@@ -1908,9 +1940,15 @@
         AutofillMetrics::AUTOCHECKOUT_CANCELLED);
   }
   callback_.Run(NULL, std::string());
+  return true;
 }
 
-void AutofillDialogControllerImpl::OnAccept() {
+bool AutofillDialogControllerImpl::OnAccept() {
+  // If autocheckout has already started, the only thing left to do is to
+  // close the dialog.
+  if (autocheckout_state_ != AUTOCHECKOUT_NOT_STARTED)
+    return true;
+
   choose_another_instrument_or_address_ = false;
   wallet_server_validation_recoverable_ = true;
   HidePopup();
@@ -1929,13 +1967,15 @@
     }
   }
 
+  if (GetDialogType() == DIALOG_TYPE_AUTOCHECKOUT)
+    DeemphasizeRenderView();
+
   SetIsSubmitting(true);
   if (IsSubmitPausedOn(wallet::VERIFY_CVV)) {
     DCHECK(!active_instrument_id_.empty());
     GetWalletClient()->AuthenticateInstrument(
         active_instrument_id_,
-        UTF16ToUTF8(view_->GetCvc()),
-        wallet_items_->obfuscated_gaia_id());
+        UTF16ToUTF8(view_->GetCvc()));
   } else if (IsPayingWithWallet()) {
     // TODO(dbeam): disallow interacting with the dialog while submitting.
     // http://crbug.com/230932
@@ -1943,6 +1983,8 @@
   } else {
     FinishSubmit();
   }
+
+  return false;
 }
 
 Profile* AutofillDialogControllerImpl::profile() {
@@ -2025,6 +2067,20 @@
 }
 
 ////////////////////////////////////////////////////////////////////////////////
+// content::WebContentsObserver implementation.
+
+void AutofillDialogControllerImpl::DidNavigateMainFrame(
+    const content::LoadCommittedDetails& details,
+    const content::FrameNavigateParams& params) {
+  // Close view if necessary.
+  if (!net::registry_controlled_domains::SameDomainOrHost(
+          details.previous_url, details.entry->GetURL(),
+          net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES)) {
+    Hide();
+  }
+}
+
+////////////////////////////////////////////////////////////////////////////////
 // SuggestionsMenuModelDelegate implementation.
 
 void AutofillDialogControllerImpl::SuggestionItemSelected(
@@ -2172,61 +2228,25 @@
   OnWalletOrSigninUpdate();
 }
 
-void AutofillDialogControllerImpl::OnDidSaveAddress(
+void AutofillDialogControllerImpl::OnDidSaveToWallet(
+    const std::string& instrument_id,
     const std::string& address_id,
     const std::vector<wallet::RequiredAction>& required_actions,
     const std::vector<wallet::FormFieldError>& form_field_errors) {
   DCHECK(is_submitting_ && IsPayingWithWallet());
 
   if (required_actions.empty()) {
-    active_address_id_ = address_id;
-    GetFullWalletIfReady();
+    if (!address_id.empty())
+      active_address_id_ = address_id;
+    if (!instrument_id.empty())
+      active_instrument_id_ = instrument_id;
+    GetFullWallet();
   } else {
     OnWalletFormFieldError(form_field_errors);
     HandleSaveOrUpdateRequiredActions(required_actions);
   }
 }
 
-void AutofillDialogControllerImpl::OnDidSaveInstrument(
-    const std::string& instrument_id,
-    const std::vector<wallet::RequiredAction>& required_actions,
-    const std::vector<wallet::FormFieldError>& form_field_errors) {
-  DCHECK(is_submitting_ && IsPayingWithWallet());
-
-  if (required_actions.empty()) {
-    active_instrument_id_ = instrument_id;
-    GetFullWalletIfReady();
-  } else {
-    OnWalletFormFieldError(form_field_errors);
-    HandleSaveOrUpdateRequiredActions(required_actions);
-  }
-}
-
-void AutofillDialogControllerImpl::OnDidSaveInstrumentAndAddress(
-    const std::string& instrument_id,
-    const std::string& address_id,
-    const std::vector<wallet::RequiredAction>& required_actions,
-    const std::vector<wallet::FormFieldError>& form_field_errors) {
-  OnDidSaveInstrument(instrument_id, required_actions, form_field_errors);
-  // |is_submitting_| can change while in |OnDidSaveInstrument()|.
-  if (is_submitting_)
-    OnDidSaveAddress(address_id, required_actions, form_field_errors);
-}
-
-void AutofillDialogControllerImpl::OnDidUpdateAddress(
-    const std::string& address_id,
-    const std::vector<wallet::RequiredAction>& required_actions,
-    const std::vector<wallet::FormFieldError>& form_field_errors) {
-  OnDidSaveAddress(address_id, required_actions, form_field_errors);
-}
-
-void AutofillDialogControllerImpl::OnDidUpdateInstrument(
-    const std::string& instrument_id,
-    const std::vector<wallet::RequiredAction>& required_actions,
-    const std::vector<wallet::FormFieldError>& form_field_errors) {
-  OnDidSaveInstrument(instrument_id, required_actions, form_field_errors);
-}
-
 void AutofillDialogControllerImpl::OnWalletError(
     wallet::WalletClient::ErrorType error_type) {
   DisableWallet(error_type);
@@ -2294,7 +2314,8 @@
     const DialogType dialog_type,
     const base::Callback<void(const FormStructure*,
                               const std::string&)>& callback)
-    : profile_(Profile::FromBrowserContext(contents->GetBrowserContext())),
+    : WebContentsObserver(contents),
+      profile_(Profile::FromBrowserContext(contents->GetBrowserContext())),
       contents_(contents),
       initial_user_state_(AutofillMetrics::DIALOG_USER_STATE_UNKNOWN),
       dialog_type_(dialog_type),
@@ -2321,7 +2342,8 @@
       choose_another_instrument_or_address_(false),
       wallet_server_validation_recoverable_(true),
       autocheckout_state_(AUTOCHECKOUT_NOT_STARTED),
-      was_ui_latency_logged_(false) {
+      was_ui_latency_logged_(false),
+      deemphasized_render_view_(false) {
   // TODO(estade): remove duplicates from |form_structure|?
   DCHECK(!callback_.is_null());
 }
@@ -3004,17 +3026,16 @@
 
   scoped_ptr<wallet::Instrument> inputted_instrument =
       CreateTransientInstrument();
-  scoped_ptr<wallet::WalletClient::UpdateInstrumentRequest> update_request =
-      CreateUpdateInstrumentRequest(
-          inputted_instrument.get(),
-          !IsEditingExistingData(SECTION_CC_BILLING) ? std::string() :
-              active_instrument->object_id());
+  if (inputted_instrument && IsEditingExistingData(SECTION_CC_BILLING)) {
+    inputted_instrument->set_object_id(active_instrument->object_id());
+    DCHECK(!inputted_instrument->object_id().empty());
+  }
 
   scoped_ptr<wallet::Address> inputted_address;
   if (active_address_id_.empty()) {
     if (ShouldUseBillingForShipping()) {
       const wallet::Address& address = inputted_instrument ?
-          inputted_instrument->address() : active_instrument->address();
+          *inputted_instrument->address() : active_instrument->address();
       // Try to find an exact matched shipping address and use it for shipping,
       // otherwise save it as a new shipping address. http://crbug.com/225442
       const wallet::Address* duplicated_address =
@@ -3042,36 +3063,9 @@
     return;
   }
 
-  // If instrument and address aren't based off of any existing data, save both.
-  if (inputted_instrument && inputted_address && !update_request &&
-      inputted_address->object_id().empty()) {
-    GetWalletClient()->SaveInstrumentAndAddress(
-        *inputted_instrument,
-        *inputted_address,
-        wallet_items_->obfuscated_gaia_id(),
-        source_url_);
-    return;
-  }
-
-  if (inputted_instrument) {
-    if (update_request) {
-      scoped_ptr<wallet::Address> billing_address(
-          new wallet::Address(inputted_instrument->address()));
-      GetWalletClient()->UpdateInstrument(*update_request,
-                                          billing_address.Pass());
-    } else {
-      GetWalletClient()->SaveInstrument(*inputted_instrument,
-                                        wallet_items_->obfuscated_gaia_id(),
-                                        source_url_);
-    }
-  }
-
-  if (inputted_address) {
-    if (!inputted_address->object_id().empty())
-      GetWalletClient()->UpdateAddress(*inputted_address, source_url_);
-    else
-      GetWalletClient()->SaveAddress(*inputted_address, source_url_);
-  }
+  GetWalletClient()->SaveToWallet(inputted_instrument.Pass(),
+                                  inputted_address.Pass(),
+                                  source_url_);
 }
 
 scoped_ptr<wallet::Instrument> AutofillDialogControllerImpl::
@@ -3091,24 +3085,6 @@
       new wallet::Instrument(card, cvc, profile));
 }
 
-scoped_ptr<wallet::WalletClient::UpdateInstrumentRequest>
-    AutofillDialogControllerImpl::CreateUpdateInstrumentRequest(
-        const wallet::Instrument* instrument,
-        const std::string& instrument_id) {
-  if (!instrument || instrument_id.empty())
-    return scoped_ptr<wallet::WalletClient::UpdateInstrumentRequest>();
-
-  scoped_ptr<wallet::WalletClient::UpdateInstrumentRequest> update_request(
-      new wallet::WalletClient::UpdateInstrumentRequest(
-          instrument_id, source_url_));
-  update_request->expiration_month = instrument->expiration_month();
-  update_request->expiration_year = instrument->expiration_year();
-  update_request->card_verification_number =
-      UTF16ToUTF8(instrument->card_verification_number());
-  update_request->obfuscated_gaia_id = wallet_items_->obfuscated_gaia_id();
-  return update_request.Pass();
-}
-
 scoped_ptr<wallet::Address>AutofillDialogControllerImpl::
     CreateTransientAddress() {
   // If not using billing for shipping, just scrape the view.
@@ -3142,14 +3118,6 @@
       capabilities));
 }
 
-void AutofillDialogControllerImpl::GetFullWalletIfReady() {
-  DCHECK(is_submitting_);
-  DCHECK(IsPayingWithWallet());
-
-  if (!active_instrument_id_.empty() && !active_address_id_.empty())
-    GetFullWallet();
-}
-
 void AutofillDialogControllerImpl::HandleSaveOrUpdateRequiredActions(
     const std::vector<wallet::RequiredAction>& required_actions) {
   DCHECK(!required_actions.empty());
@@ -3403,6 +3371,13 @@
   }
 }
 
+void AutofillDialogControllerImpl::DeemphasizeRenderView() {
+  web_contents()->GetRenderViewHost()->Send(
+      new ChromeViewMsg_SetVisuallyDeemphasized(
+          web_contents()->GetRenderViewHost()->GetRoutingID(), true));
+  deemphasized_render_view_ = true;
+}
+
 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 a8c578d..eadf103 100644
--- a/chrome/browser/ui/autofill/autofill_dialog_controller_impl.h
+++ b/chrome/browser/ui/autofill/autofill_dialog_controller_impl.h
@@ -33,6 +33,7 @@
 #include "components/autofill/core/browser/personal_data_manager_observer.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
+#include "content/public/browser/web_contents_observer.h"
 #include "content/public/common/ssl_status.h"
 #include "ui/base/models/simple_menu_model.h"
 #include "ui/base/ui_base_types.h"
@@ -69,6 +70,7 @@
 class AutofillDialogControllerImpl : public AutofillDialogController,
                                      public AutofillPopupDelegate,
                                      public content::NotificationObserver,
+                                     public content::WebContentsObserver,
                                      public SuggestionsMenuModelDelegate,
                                      public wallet::WalletClientDelegate,
                                      public wallet::WalletSigninHelperDelegate,
@@ -90,9 +92,6 @@
   void Show();
   void Hide();
 
-  // Whether Autocheckout is currently running.
-  bool AutocheckoutIsRunning() const;
-
   // Adds a step in the flow to the Autocheckout UI.
   void AddAutocheckoutStep(AutocheckoutStepType step_type);
 
@@ -173,8 +172,8 @@
                                                 bool checked) OVERRIDE;
   virtual void LegalDocumentLinkClicked(const ui::Range& range) OVERRIDE;
   virtual void OverlayButtonPressed() OVERRIDE;
-  virtual void OnCancel() OVERRIDE;
-  virtual void OnAccept() OVERRIDE;
+  virtual bool OnCancel() OVERRIDE;
+  virtual bool OnAccept() OVERRIDE;
   virtual Profile* profile() OVERRIDE;
   virtual content::WebContents* web_contents() OVERRIDE;
 
@@ -193,6 +192,11 @@
                        const content::NotificationSource& source,
                        const content::NotificationDetails& details) OVERRIDE;
 
+  // content::WebContentsObserver implementation.
+  virtual void DidNavigateMainFrame(
+      const content::LoadCommittedDetails& details,
+      const content::FrameNavigateParams& params) OVERRIDE;
+
   // SuggestionsMenuModelDelegate implementation.
   virtual void SuggestionItemSelected(SuggestionsMenuModel* model,
                                       size_t index) OVERRIDE;
@@ -208,27 +212,11 @@
       scoped_ptr<wallet::FullWallet> full_wallet) OVERRIDE;
   virtual void OnDidGetWalletItems(
       scoped_ptr<wallet::WalletItems> wallet_items) OVERRIDE;
-  virtual void OnDidSaveAddress(
-      const std::string& address_id,
-      const std::vector<wallet::RequiredAction>& required_actions,
-      const std::vector<wallet::FormFieldError>& form_field_errors) OVERRIDE;
-  virtual void OnDidSaveInstrument(
-      const std::string& instrument_id,
-      const std::vector<wallet::RequiredAction>& required_actions,
-      const std::vector<wallet::FormFieldError>& form_field_errors) OVERRIDE;
-  virtual void OnDidSaveInstrumentAndAddress(
+  virtual void OnDidSaveToWallet(
       const std::string& instrument_id,
       const std::string& address_id,
       const std::vector<wallet::RequiredAction>& required_actions,
       const std::vector<wallet::FormFieldError>& form_field_errors) OVERRIDE;
-  virtual void OnDidUpdateAddress(
-      const std::string& address_id,
-      const std::vector<wallet::RequiredAction>& required_actions,
-      const std::vector<wallet::FormFieldError>& form_field_errors) OVERRIDE;
-  virtual void OnDidUpdateInstrument(
-      const std::string& instrument_id,
-      const std::vector<wallet::RequiredAction>& required_actions,
-      const std::vector<wallet::FormFieldError>& form_field_errors) OVERRIDE;
   virtual void OnWalletError(
       wallet::WalletClient::ErrorType error_type) OVERRIDE;
 
@@ -306,6 +294,8 @@
   // to the requesting site.
   virtual bool TransmissionWillBeSecure() const;
 
+  AutocheckoutState autocheckout_state() const { return autocheckout_state_; }
+
  private:
   // Whether or not the current request wants credit info back.
   bool RequestingCreditCardInfo() const;
@@ -492,11 +482,6 @@
   // Creates an instrument based on |views_|' contents.
   scoped_ptr<wallet::Instrument> CreateTransientInstrument();
 
-  // Creates an update request based on |instrument|. May return NULL.
-  scoped_ptr<wallet::WalletClient::UpdateInstrumentRequest>
-      CreateUpdateInstrumentRequest(const wallet::Instrument* instrument,
-                                    const std::string& instrument_id);
-
   // Creates an address based on the contents of |view_|.
   scoped_ptr<wallet::Address> CreateTransientAddress();
 
@@ -504,10 +489,6 @@
   // This information is decoded to reveal a fronting (proxy) card.
   void GetFullWallet();
 
-  // Calls |GetFullWallet()| if the required members (|risk_data_|,
-  // |active_instrument_id_|, and |active_address_id_|) are populated.
-  void GetFullWalletIfReady();
-
   // Updates the state of the controller and |view_| based on any required
   // actions returned by Save or Update calls to Wallet.
   void HandleSaveOrUpdateRequiredActions(
@@ -559,6 +540,9 @@
   // Sets the state of the autocheckout flow.
   void SetAutocheckoutState(AutocheckoutState autocheckout_state);
 
+  // Obscures the web contents.
+  void DeemphasizeRenderView();
+
   // Returns the metric corresponding to the user's initial state when
   // interacting with this dialog.
   AutofillMetrics::DialogInitialUserStateMetric GetInitialUserState() const;
@@ -707,6 +691,9 @@
   // Whether the latency to display to the UI was logged to UMA yet.
   bool was_ui_latency_logged_;
 
+  // Whether or not the render view has been deemphasized.
+  bool deemphasized_render_view_;
+
   // State of steps in the current Autocheckout flow, or empty if not an
   // Autocheckout use case.
   std::vector<DialogAutocheckoutStep> steps_;
diff --git a/chrome/browser/ui/autofill/autofill_dialog_controller_unittest.cc b/chrome/browser/ui/autofill/autofill_dialog_controller_unittest.cc
index f12a833..142e7d0 100644
--- a/chrome/browser/ui/autofill/autofill_dialog_controller_unittest.cc
+++ b/chrome/browser/ui/autofill/autofill_dialog_controller_unittest.cc
@@ -13,11 +13,14 @@
 #include "base/run_loop.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/tuple.h"
 #include "chrome/browser/ui/autofill/autofill_credit_card_bubble_controller.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/test_autofill_credit_card_bubble.h"
 #include "chrome/common/pref_names.h"
+#include "chrome/common/render_messages.h"
+#include "chrome/test/base/chrome_render_view_host_test_harness.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/autofill/content/browser/risk/proto/fingerprint.pb.h"
 #include "components/autofill/content/browser/wallet/full_wallet.h"
@@ -32,8 +35,7 @@
 #include "components/autofill/core/common/autofill_switches.h"
 #include "components/autofill/core/common/form_data.h"
 #include "content/public/browser/web_contents.h"
-#include "content/public/test/test_browser_thread_bundle.h"
-#include "content/public/test/web_contents_tester.h"
+#include "content/public/test/mock_render_process_host.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -236,6 +238,10 @@
     OnWalletSigninError();
   }
 
+  bool AutocheckoutIsRunning() const {
+    return AUTOCHECKOUT_IN_PROGRESS == autocheckout_state();
+  }
+
   MOCK_METHOD0(LoadRiskFingerprintData, void());
   using AutofillDialogControllerImpl::OnDidLoadRiskFingerprintData;
   using AutofillDialogControllerImpl::IsEditingExistingData;
@@ -307,19 +313,18 @@
   DISALLOW_COPY_AND_ASSIGN(TestAutofillCreditCardBubbleController);
 };
 
-class AutofillDialogControllerTest : public testing::Test {
+class AutofillDialogControllerTest : public ChromeRenderViewHostTestHarness {
  protected:
   AutofillDialogControllerTest(): form_structure_(NULL) {}
 
   // testing::Test implementation:
   virtual void SetUp() OVERRIDE {
+    ChromeRenderViewHostTestHarness::SetUp();
     profile()->CreateRequestContext();
-    test_web_contents_.reset(
-        content::WebContentsTester::CreateTestWebContents(profile(), NULL));
 
     test_bubble_controller_ =
         new testing::NiceMock<TestAutofillCreditCardBubbleController>(
-            test_web_contents_.get());
+            web_contents());
 
     // Don't get stuck on the first run wallet interstitial.
     profile()->GetPrefs()->SetBoolean(::prefs::kAutofillDialogHasPaidWithWallet,
@@ -331,9 +336,25 @@
   virtual void TearDown() OVERRIDE {
     if (controller_)
       controller_->ViewClosed();
+    ChromeRenderViewHostTestHarness::TearDown();
   }
 
- protected:
+  void Reset() {
+    if (controller_)
+      controller_->ViewClosed();
+    profile()->CreateRequestContext();
+
+    test_bubble_controller_ =
+        new testing::NiceMock<TestAutofillCreditCardBubbleController>(
+            web_contents());
+
+    // Don't get stuck on the first run wallet interstitial.
+    profile()->GetPrefs()->SetBoolean(::prefs::kAutofillDialogHasPaidWithWallet,
+                                      true);
+
+    SetUpControllerWithFormData(DefaultFormData());
+  }
+
   FormData DefaultFormData() {
     FormData form_data;
     for (size_t i = 0; i < arraysize(kFieldsFromPage); ++i) {
@@ -352,7 +373,7 @@
         base::Bind(&AutofillDialogControllerTest::FinishedCallback,
                    base::Unretained(this));
     controller_ = (new testing::NiceMock<TestAutofillDialogController>(
-        test_web_contents_.get(),
+        web_contents(),
         form_data,
         GURL(),
         metric_logger_,
@@ -427,16 +448,22 @@
     controller()->OnDidLoadRiskFingerprintData(GetFakeFingerprint().Pass());
   }
 
+  bool ReadSetVisuallyDeemphasizedIpc() {
+    EXPECT_EQ(1U, process()->sink().message_count());
+    uint32 kMsgID = ChromeViewMsg_SetVisuallyDeemphasized::ID;
+    const IPC::Message* message =
+        process()->sink().GetFirstMessageMatching(kMsgID);
+    EXPECT_TRUE(message);
+    Tuple1<bool> payload;
+    ChromeViewMsg_SetVisuallyDeemphasized::Read(message, &payload);
+    process()->sink().ClearMessages();
+    return payload.a;
+  }
+
   TestAutofillDialogController* controller() { return controller_.get(); }
 
-  TestingProfile* profile() { return &profile_; }
-
   const FormStructure* form_structure() { return form_structure_; }
 
-  const content::WebContents* test_web_contents() const {
-    return test_web_contents_.get();
-  }
-
   TestAutofillCreditCardBubbleController* test_bubble_controller() {
     return test_bubble_controller_;
   }
@@ -449,21 +476,14 @@
       EXPECT_TRUE(controller()->AutocheckoutIsRunning());
   }
 
-  // Must be first member to ensure TestBrowserThreads outlive other objects.
-  content::TestBrowserThreadBundle thread_bundle_;
-
 #if defined(OS_WIN)
    // http://crbug.com/227221
    ui::ScopedOleInitializer ole_initializer_;
 #endif
 
-  TestingProfile profile_;
-
   // The controller owns itself.
   base::WeakPtr<TestAutofillDialogController> controller_;
 
-  scoped_ptr<content::WebContents> test_web_contents_;
-
   // Must outlive the controller.
   AutofillMetrics metric_logger_;
 
@@ -471,7 +491,7 @@
   const FormStructure* form_structure_;
 
   // Used to monitor if the Autofill credit card bubble is shown. Owned by
-  // |test_web_contents_|.
+  // |web_contents()|.
   TestAutofillCreditCardBubbleController* test_bubble_controller_;
 };
 
@@ -742,8 +762,7 @@
     FillCreditCardInputs();
     controller()->OnAccept();
 
-    TearDown();
-    SetUp();
+    Reset();
     controller()->GetTestingManager()->AddTestingProfile(&full_profile);
     controller()->GetTestingManager()->AddTestingProfile(&full_profile2);
     shipping_model = static_cast<SuggestionsMenuModel*>(
@@ -756,8 +775,7 @@
   shipping_model->ExecuteCommand(2, 0);
   FillCreditCardInputs();
   controller()->OnAccept();
-  TearDown();
-  SetUp();
+  Reset();
   controller()->GetTestingManager()->AddTestingProfile(&full_profile);
   shipping_model = static_cast<SuggestionsMenuModel*>(
       controller()->MenuModelForSection(SECTION_SHIPPING));
@@ -815,8 +833,7 @@
   FillCreditCardInputs();
   controller()->OnAccept();
 
-  TearDown();
-  SetUp();
+  Reset();
   controller()->GetTestingManager()->AddTestingProfile(&full_profile);
   email_suggestions = static_cast<SuggestionsMenuModel*>(
       controller()->MenuModelForSection(SECTION_EMAIL));
@@ -1109,7 +1126,9 @@
 TEST_F(AutofillDialogControllerTest, SaveAddress) {
   EXPECT_CALL(*controller()->GetView(), ModelChanged()).Times(1);
   EXPECT_CALL(*controller()->GetTestingWalletClient(),
-              SaveAddress(_, _)).Times(1);
+              SaveToWalletMock(testing::IsNull(),
+                               testing::NotNull(),
+                               _)).Times(1);
 
   scoped_ptr<wallet::WalletItems> wallet_items = wallet::GetTestWalletItems();
   wallet_items->AddInstrument(wallet::GetTestMaskedInstrument());
@@ -1126,7 +1145,9 @@
 TEST_F(AutofillDialogControllerTest, SaveInstrument) {
   EXPECT_CALL(*controller()->GetView(), ModelChanged()).Times(1);
   EXPECT_CALL(*controller()->GetTestingWalletClient(),
-              SaveInstrument(_, _, _)).Times(1);
+              SaveToWalletMock(testing::NotNull(),
+                               testing::IsNull(),
+                               _)).Times(1);
 
   scoped_ptr<wallet::WalletItems> wallet_items = wallet::GetTestWalletItems();
   wallet_items->AddAddress(wallet::GetTestShippingAddress());
@@ -1136,7 +1157,9 @@
 TEST_F(AutofillDialogControllerTest, SaveInstrumentWithInvalidInstruments) {
   EXPECT_CALL(*controller()->GetView(), ModelChanged()).Times(1);
   EXPECT_CALL(*controller()->GetTestingWalletClient(),
-              SaveInstrument(_, _, _)).Times(1);
+              SaveToWalletMock(testing::NotNull(),
+                               testing::IsNull(),
+                               _)).Times(1);
 
   scoped_ptr<wallet::WalletItems> wallet_items = wallet::GetTestWalletItems();
   wallet_items->AddAddress(wallet::GetTestShippingAddress());
@@ -1146,17 +1169,25 @@
 
 TEST_F(AutofillDialogControllerTest, SaveInstrumentAndAddress) {
   EXPECT_CALL(*controller()->GetTestingWalletClient(),
-              SaveInstrumentAndAddress(_, _, _, _)).Times(1);
+              SaveToWalletMock(testing::NotNull(),
+                               testing::NotNull(),
+                               _)).Times(1);
 
   controller()->OnDidGetWalletItems(wallet::GetTestWalletItems());
   AcceptAndLoadFakeFingerprint();
 }
 
+MATCHER(IsUpdatingExistingData, "updating existing Wallet data") {
+  return !arg->object_id().empty();
+}
+
 // Tests that editing an address (in wallet mode0 and submitting the dialog
 // should update the existing address on the server via WalletClient.
 TEST_F(AutofillDialogControllerTest, UpdateAddress) {
   EXPECT_CALL(*controller()->GetTestingWalletClient(),
-              UpdateAddress(_, _)).Times(1);
+              SaveToWalletMock(testing::IsNull(),
+                               IsUpdatingExistingData(),
+                               _)).Times(1);
 
   controller()->OnDidGetWalletItems(CompleteAndValidWalletItems());
 
@@ -1167,20 +1198,24 @@
 // Tests that editing an instrument (CC + address) in wallet mode updates an
 // existing instrument on the server via WalletClient.
 TEST_F(AutofillDialogControllerTest, UpdateInstrument) {
+  EXPECT_CALL(*controller()->GetTestingWalletClient(),
+              SaveToWalletMock(IsUpdatingExistingData(),
+                               testing::IsNull(),
+                               _)).Times(1);
+
   controller()->OnDidGetWalletItems(CompleteAndValidWalletItems());
 
   controller()->EditClickedForSection(SECTION_CC_BILLING);
   AcceptAndLoadFakeFingerprint();
-
-  EXPECT_TRUE(
-      controller()->GetTestingWalletClient()->updated_billing_address());
 }
 
 // Test that a user is able to edit their instrument and add a new address in
 // the same submission.
 TEST_F(AutofillDialogControllerTest, UpdateInstrumentSaveAddress) {
   EXPECT_CALL(*controller()->GetTestingWalletClient(),
-              SaveAddress(_, _)).Times(1);
+              SaveToWalletMock(IsUpdatingExistingData(),
+                               testing::NotNull(),
+                               _)).Times(1);
 
   scoped_ptr<wallet::WalletItems> wallet_items = wallet::GetTestWalletItems();
   wallet_items->AddInstrument(wallet::GetTestMaskedInstrument());
@@ -1188,17 +1223,14 @@
 
   controller()->EditClickedForSection(SECTION_CC_BILLING);
   AcceptAndLoadFakeFingerprint();
-
-  EXPECT_TRUE(
-      controller()->GetTestingWalletClient()->updated_billing_address());
 }
 
 // Test that saving a new instrument and editing an address works.
 TEST_F(AutofillDialogControllerTest, SaveInstrumentUpdateAddress) {
   EXPECT_CALL(*controller()->GetTestingWalletClient(),
-              SaveInstrument(_, _, _)).Times(1);
-  EXPECT_CALL(*controller()->GetTestingWalletClient(),
-              UpdateAddress(_, _)).Times(1);
+              SaveToWalletMock(testing::NotNull(),
+                               IsUpdatingExistingData(),
+                               _)).Times(1);
 
   scoped_ptr<wallet::WalletItems> wallet_items = wallet::GetTestWalletItems();
   wallet_items->AddAddress(wallet::GetTestShippingAddress());
@@ -1210,14 +1242,16 @@
 }
 
 MATCHER(UsesLocalBillingAddress, "uses the local billing address") {
-  return arg.address_line_1() == ASCIIToUTF16(kEditedBillingAddress);
+  return arg->address_line_1() == ASCIIToUTF16(kEditedBillingAddress);
 }
 
 // Tests that when using billing address for shipping, and there is no exact
 // matched shipping address, then a shipping address should be added.
 TEST_F(AutofillDialogControllerTest, BillingForShipping) {
   EXPECT_CALL(*controller()->GetTestingWalletClient(),
-              SaveAddress(_, _)).Times(1);
+              SaveToWalletMock(testing::IsNull(),
+                               testing::NotNull(),
+                               _)).Times(1);
 
   controller()->OnDidGetWalletItems(CompleteAndValidWalletItems());
   // Select "Same as billing" in the address menu.
@@ -1230,7 +1264,7 @@
 // matched shipping address, then a shipping address should not be added.
 TEST_F(AutofillDialogControllerTest, BillingForShippingHasMatch) {
   EXPECT_CALL(*controller()->GetTestingWalletClient(),
-              SaveAddress(_, _)).Times(0);
+              SaveToWalletMock(_, _, _)).Times(0);
 
   scoped_ptr<wallet::WalletItems> wallet_items = wallet::GetTestWalletItems();
   scoped_ptr<wallet::WalletItems::MaskedInstrument> instrument =
@@ -1250,22 +1284,6 @@
   AcceptAndLoadFakeFingerprint();
 }
 
-// Tests that adding new instrument and also using billing address for shipping,
-// then a shipping address should not be added.
-TEST_F(AutofillDialogControllerTest, BillingForShippingNewInstrument) {
-  EXPECT_CALL(*controller()->GetTestingWalletClient(),
-              SaveInstrumentAndAddress(_, _, _, _)).Times(1);
-
-  scoped_ptr<wallet::WalletItems> wallet_items = wallet::GetTestWalletItems();
-  wallet_items->AddAddress(wallet::GetTestShippingAddress());
-
-  controller()->OnDidGetWalletItems(wallet_items.Pass());
-  // Select "Same as billing" in the address menu.
-  UseBillingForShipping();
-
-  AcceptAndLoadFakeFingerprint();
-}
-
 // Test that the local view contents is used when saving a new instrument and
 // the user has selected "Same as billing".
 TEST_F(AutofillDialogControllerTest, SaveInstrumentSameAsBilling) {
@@ -1287,16 +1305,15 @@
   controller()->GetView()->SetUserInput(SECTION_CC_BILLING, outputs);
 
   EXPECT_CALL(*controller()->GetTestingWalletClient(),
-              SaveAddress(UsesLocalBillingAddress(), _)).Times(1);
+              SaveToWalletMock(testing::NotNull(),
+                               UsesLocalBillingAddress(),
+                               _)).Times(1);
   AcceptAndLoadFakeFingerprint();
-
-  EXPECT_TRUE(
-      controller()->GetTestingWalletClient()->updated_billing_address());
 }
 
 TEST_F(AutofillDialogControllerTest, CancelNoSave) {
   EXPECT_CALL(*controller()->GetTestingWalletClient(),
-              SaveInstrumentAndAddress(_, _, _, _)).Times(0);
+              SaveToWalletMock(_, _, _)).Times(0);
 
   EXPECT_CALL(*controller()->GetView(), ModelChanged()).Times(1);
 
@@ -1488,7 +1505,7 @@
   EXPECT_CALL(*controller()->GetTestingWalletClient(),
               GetFullWallet(_)).Times(1);
   EXPECT_CALL(*controller()->GetTestingWalletClient(),
-              AuthenticateInstrument(_, _, _)).Times(1);
+              AuthenticateInstrument(_, _)).Times(1);
 
   SubmitWithWalletItems(CompleteAndValidWalletItems());
 
@@ -1604,7 +1621,10 @@
                              wallet::FormFieldError::SHIPPING_ADDRESS));
 
   EXPECT_CALL(*controller()->GetView(), UpdateForErrors()).Times(1);
-  controller()->OnDidSaveAddress(std::string(), required_actions, form_errors);
+  controller()->OnDidSaveToWallet(std::string(),
+                                  std::string(),
+                                  required_actions,
+                                  form_errors);
 }
 
 // Simulates receiving unrecoverable Wallet server validation errors.
@@ -1622,7 +1642,10 @@
       wallet::FormFieldError(wallet::FormFieldError::UNKNOWN_ERROR,
                              wallet::FormFieldError::UNKNOWN_LOCATION));
 
-  controller()->OnDidSaveAddress(std::string(), required_actions, form_errors);
+  controller()->OnDidSaveToWallet(std::string(),
+                                  std::string(),
+                                  required_actions,
+                                  form_errors);
 
   EXPECT_EQ(1U, NotificationsOfType(
       DialogNotification::REQUIRED_ACTION).size());
@@ -1731,14 +1754,18 @@
   FillCreditCardInputs();
 
   controller()->OnAccept();
+  EXPECT_TRUE(ReadSetVisuallyDeemphasizedIpc());
   controller()->OnAutocheckoutError();
 
-  EXPECT_TRUE(controller()->IsDialogButtonEnabled(ui::DIALOG_BUTTON_CANCEL));
-  EXPECT_FALSE(controller()->IsDialogButtonEnabled(ui::DIALOG_BUTTON_OK));
+  EXPECT_FALSE(controller()->GetDialogButtons() & ui::DIALOG_BUTTON_CANCEL);
+  EXPECT_TRUE(controller()->IsDialogButtonEnabled(ui::DIALOG_BUTTON_OK));
   EXPECT_EQ(0U, NotificationsOfType(
       DialogNotification::AUTOCHECKOUT_SUCCESS).size());
   EXPECT_EQ(1U, NotificationsOfType(
       DialogNotification::AUTOCHECKOUT_ERROR).size());
+
+  controller()->ViewClosed();
+  EXPECT_FALSE(ReadSetVisuallyDeemphasizedIpc());
 }
 
 TEST_F(AutofillDialogControllerTest, OnAutocheckoutSuccess) {
@@ -1762,6 +1789,7 @@
       DialogNotification::WALLET_USAGE_CONFIRMATION).size());
 
   AcceptAndLoadFakeFingerprint();
+  EXPECT_TRUE(ReadSetVisuallyDeemphasizedIpc());
   controller()->OnDidGetFullWallet(wallet::GetTestFullWallet());
   EXPECT_TRUE(controller()->GetDialogOverlay().image.IsEmpty());
 
@@ -1771,8 +1799,8 @@
   controller()->OnAutocheckoutSuccess();
   EXPECT_TRUE(controller()->GetDialogOverlay().image.IsEmpty());
 
-  EXPECT_TRUE(controller()->IsDialogButtonEnabled(ui::DIALOG_BUTTON_CANCEL));
-  EXPECT_FALSE(controller()->IsDialogButtonEnabled(ui::DIALOG_BUTTON_OK));
+  EXPECT_FALSE(controller()->GetDialogButtons() & ui::DIALOG_BUTTON_CANCEL);
+  EXPECT_TRUE(controller()->IsDialogButtonEnabled(ui::DIALOG_BUTTON_OK));
   EXPECT_EQ(1U, NotificationsOfType(
       DialogNotification::AUTOCHECKOUT_SUCCESS).size());
   EXPECT_EQ(0U, NotificationsOfType(
@@ -1781,6 +1809,9 @@
       DialogNotification::EXPLANATORY_MESSAGE).size());
   EXPECT_TRUE(profile()->GetPrefs()->GetBoolean(
       ::prefs::kAutofillDialogHasPaidWithWallet));
+
+  controller()->ViewClosed();
+  EXPECT_FALSE(ReadSetVisuallyDeemphasizedIpc());
 }
 
 TEST_F(AutofillDialogControllerTest, ViewCancelDoesntSetPref) {
@@ -2156,6 +2187,7 @@
   // Initiate flow - should add proxy card step since the user is using wallet
   // data.
   controller()->OnAccept();
+  EXPECT_TRUE(ReadSetVisuallyDeemphasizedIpc());
   controller()->OnDidLoadRiskFingerprintData(GetFakeFingerprint().Pass());
 
   SuggestionState suggestion_state =
@@ -2186,6 +2218,7 @@
 
   // Re-initiate flow.
   controller()->OnAccept();
+  EXPECT_TRUE(ReadSetVisuallyDeemphasizedIpc());
 
   // All steps should be initially unstarted.
   EXPECT_EQ(3U, controller()->CurrentAutocheckoutSteps().size());
@@ -2225,6 +2258,9 @@
             controller()->CurrentAutocheckoutSteps()[2].type());
   EXPECT_EQ(AUTOCHECKOUT_STEP_UNSTARTED,
             controller()->CurrentAutocheckoutSteps()[2].status());
+
+  controller()->ViewClosed();
+  EXPECT_FALSE(ReadSetVisuallyDeemphasizedIpc());
 }
 
 
diff --git a/chrome/browser/ui/autofill/autofill_dialog_types.cc b/chrome/browser/ui/autofill/autofill_dialog_types.cc
index 1230c53..6a2a4a2 100644
--- a/chrome/browser/ui/autofill/autofill_dialog_types.cc
+++ b/chrome/browser/ui/autofill/autofill_dialog_types.cc
@@ -50,7 +50,7 @@
     case DialogNotification::REQUIRED_ACTION:
     case DialogNotification::WALLET_ERROR:
     case DialogNotification::AUTOCHECKOUT_ERROR:
-      return SK_ColorBLACK;
+      return SkColorSetRGB(102, 102, 102);
     case DialogNotification::AUTOCHECKOUT_SUCCESS:
     case DialogNotification::DEVELOPER_WARNING:
     case DialogNotification::EXPLANATORY_MESSAGE:
diff --git a/chrome/browser/ui/autofill/autofill_dialog_types.h b/chrome/browser/ui/autofill/autofill_dialog_types.h
index 26df627..c67a88b 100644
--- a/chrome/browser/ui/autofill/autofill_dialog_types.h
+++ b/chrome/browser/ui/autofill/autofill_dialog_types.h
@@ -173,7 +173,7 @@
   AUTOCHECKOUT_ERROR,        // There was an error in the flow.
   AUTOCHECKOUT_IN_PROGRESS,  // The flow is currently in.
   AUTOCHECKOUT_NOT_STARTED,  // The flow has not been initiated by the user yet.
-  AUTOCHECKOUT_SUCCESS,      // The flow completed successsfully.
+  AUTOCHECKOUT_SUCCESS,      // The flow completed successfully.
 };
 
 struct SuggestionState {
diff --git a/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc b/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc
index 681c2d8..d7bfd83 100644
--- a/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc
+++ b/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc
@@ -170,6 +170,62 @@
   delegate_->OnPopupShown(this);
 }
 
+void AutofillPopupControllerImpl::UpdateDataListValues(
+    const std::vector<base::string16>& values,
+    const std::vector<base::string16>& labels) {
+  // Remove all the old data list values, which should always be at the top of
+  // the list if they are present.
+  while (!identifiers_.empty() &&
+         identifiers_[0] == WebAutofillClient::MenuItemIDDataListEntry) {
+    names_.erase(names_.begin());
+    subtexts_.erase(subtexts_.begin());
+    icons_.erase(icons_.begin());
+    identifiers_.erase(identifiers_.begin());
+  }
+
+  // If there are no new data list values, exit (clearing the separator if there
+  // is one).
+  if (values.empty()) {
+    if (!identifiers_.empty() &&
+        identifiers_[0] == WebAutofillClient::MenuItemIDSeparator) {
+      names_.erase(names_.begin());
+      subtexts_.erase(subtexts_.begin());
+      icons_.erase(icons_.begin());
+      identifiers_.erase(identifiers_.begin());
+    }
+
+     // The popup contents have changed, so either update the bounds or hide it.
+    if (HasSuggestions())
+      UpdateBoundsAndRedrawPopup();
+    else
+      Hide();
+
+    return;
+  }
+
+  // Add a separator if there are any other values.
+  if (!identifiers_.empty() &&
+      identifiers_[0] != WebAutofillClient::MenuItemIDSeparator) {
+    names_.insert(names_.begin(), string16());
+    subtexts_.insert(subtexts_.begin(), string16());
+    icons_.insert(icons_.begin(), string16());
+    identifiers_.insert(identifiers_.begin(),
+                        WebAutofillClient::MenuItemIDSeparator);
+  }
+
+
+  names_.insert(names_.begin(), values.begin(), values.end());
+  subtexts_.insert(subtexts_.begin(), labels.begin(), labels.end());
+
+  // Add the values that are the same for all data list elements.
+  icons_.insert(icons_.begin(), values.size(), base::string16());
+  identifiers_.insert(identifiers_.begin(),
+                      values.size(),
+                      WebAutofillClient::MenuItemIDDataListEntry);
+
+  UpdateBoundsAndRedrawPopup();
+}
+
 void AutofillPopupControllerImpl::Hide() {
   if (delegate_.get())
     delegate_->OnPopupHidden(this);
diff --git a/chrome/browser/ui/autofill/autofill_popup_controller_impl.h b/chrome/browser/ui/autofill/autofill_popup_controller_impl.h
index 8aa1e8f..8509a9f 100644
--- a/chrome/browser/ui/autofill/autofill_popup_controller_impl.h
+++ b/chrome/browser/ui/autofill/autofill_popup_controller_impl.h
@@ -50,6 +50,10 @@
             const std::vector<string16>& icons,
             const std::vector<int>& identifiers);
 
+  // Updates the data list values currently shown with the popup.
+  void UpdateDataListValues(const std::vector<base::string16>& values,
+                            const std::vector<base::string16>& labels);
+
   // Hides the popup and destroys the controller. This also invalidates
   // |delegate_|.
   virtual void Hide() OVERRIDE;
diff --git a/chrome/browser/ui/autofill/autofill_popup_controller_unittest.cc b/chrome/browser/ui/autofill/autofill_popup_controller_unittest.cc
index 482d838..8cbcdeb 100644
--- a/chrome/browser/ui/autofill/autofill_popup_controller_unittest.cc
+++ b/chrome/browser/ui/autofill/autofill_popup_controller_unittest.cc
@@ -90,6 +90,9 @@
   const std::vector<string16>& subtexts() const {
     return AutofillPopupControllerImpl::subtexts();
   }
+  const std::vector<int>& identifiers() const {
+    return AutofillPopupControllerImpl::identifiers();
+  }
   int selected_line() const {
     return AutofillPopupControllerImpl::selected_line();
   }
@@ -366,6 +369,91 @@
             autofill_popup_controller_->RowWidthWithoutText(3));
 }
 
+TEST_F(AutofillPopupControllerUnitTest, UpdateDataListValues) {
+  std::vector<string16> items;
+  items.push_back(string16());
+  std::vector<int> ids;
+  ids.push_back(1);
+
+  autofill_popup_controller_->Show(items, items, items, ids);
+
+  EXPECT_EQ(items, autofill_popup_controller_->names());
+  EXPECT_EQ(ids, autofill_popup_controller_->identifiers());
+
+  // Add one data list entry.
+  std::vector<string16> data_list_values;
+  data_list_values.push_back(ASCIIToUTF16("data list value 1"));
+
+  autofill_popup_controller_->UpdateDataListValues(data_list_values,
+                                                   data_list_values);
+
+  // Update the expected values.
+  items.insert(items.begin(), data_list_values[0]);
+  items.insert(items.begin() + 1, string16());
+  ids.insert(ids.begin(), WebAutofillClient::MenuItemIDDataListEntry);
+  ids.insert(ids.begin() + 1, WebAutofillClient::MenuItemIDSeparator);
+
+  EXPECT_EQ(items, autofill_popup_controller_->names());
+  EXPECT_EQ(ids, autofill_popup_controller_->identifiers());
+
+  // Add two data list entries (which should replace the current one).
+  data_list_values.push_back(ASCIIToUTF16("data list value 2"));
+
+  autofill_popup_controller_->UpdateDataListValues(data_list_values,
+                                                   data_list_values);
+
+  // Update the expected values.
+  items.insert(items.begin() + 1, data_list_values[1]);
+  ids.insert(ids.begin(), WebAutofillClient::MenuItemIDDataListEntry);
+
+  EXPECT_EQ(items, autofill_popup_controller_->names());
+  EXPECT_EQ(ids, autofill_popup_controller_->identifiers());
+
+  // Clear all data list values.
+  data_list_values.clear();
+
+  autofill_popup_controller_->UpdateDataListValues(data_list_values,
+                                                   data_list_values);
+
+  items.clear();
+  items.push_back(string16());
+  ids.clear();
+  ids.push_back(1);
+
+  EXPECT_EQ(items, autofill_popup_controller_->names());
+  EXPECT_EQ(ids, autofill_popup_controller_->identifiers());
+}
+
+TEST_F(AutofillPopupControllerUnitTest, PopupsWithOnlyDataLists) {
+  // Create the popup with a single datalist element.
+  std::vector<string16> items;
+  items.push_back(string16());
+  std::vector<int> ids;
+  ids.push_back(WebAutofillClient::MenuItemIDDataListEntry);
+
+  autofill_popup_controller_->Show(items, items, items, ids);
+
+  EXPECT_EQ(items, autofill_popup_controller_->names());
+  EXPECT_EQ(ids, autofill_popup_controller_->identifiers());
+
+  // Replace the datalist element with a new one.
+  std::vector<string16> data_list_values;
+  data_list_values.push_back(ASCIIToUTF16("data list value 1"));
+
+  autofill_popup_controller_->UpdateDataListValues(data_list_values,
+                                                   data_list_values);
+
+  EXPECT_EQ(data_list_values, autofill_popup_controller_->names());
+  // The id value should stay the same.
+  EXPECT_EQ(ids, autofill_popup_controller_->identifiers());
+
+  // Clear datalist values and check that the popup becomes hidden.
+  EXPECT_CALL(*autofill_popup_controller_, Hide());
+  data_list_values.clear();
+  autofill_popup_controller_->UpdateDataListValues(data_list_values,
+                                                   data_list_values);
+}
+
 TEST_F(AutofillPopupControllerUnitTest, GetOrCreate) {
   AutofillDriverImpl* driver =
       AutofillDriverImpl::FromWebContents(web_contents());
diff --git a/chrome/browser/ui/autofill/mock_autofill_dialog_controller.cc b/chrome/browser/ui/autofill/mock_autofill_dialog_controller.cc
index 6ca8614..3718086 100644
--- a/chrome/browser/ui/autofill/mock_autofill_dialog_controller.cc
+++ b/chrome/browser/ui/autofill/mock_autofill_dialog_controller.cc
@@ -3,15 +3,32 @@
 // found in the LICENSE file.
 
 #include "chrome/browser/ui/autofill/mock_autofill_dialog_controller.h"
+#include "content/public/browser/native_web_keyboard_event.h"  // For gmock.
 #include "grit/generated_resources.h"
-#include "testing/gmock/include/gmock/gmock.h"
+#include "ui/gfx/rect.h"  // Only needed because gmock needs complete types.
 
 namespace autofill {
 
 MockAutofillDialogController::MockAutofillDialogController() {
-  testing::DefaultValue<const DetailInputs&>::Set(default_inputs_);
-  testing::DefaultValue<ui::ComboboxModel*>::Set(NULL);
-  testing::DefaultValue<ValidityData>::Set(ValidityData());
+  using testing::DefaultValue;
+  using testing::_;
+  using testing::Return;
+  using testing::ReturnRef;
+
+  // N.B. Setting DefaultValue in the ctor and deleting it in the dtor will
+  // only work if this Mock is not used together with other mock code that
+  // sets different defaults. If tests utilizing the MockController start
+  // breaking because of this, use ON_CALL instead.
+  DefaultValue<const DetailInputs&>::Set(default_inputs_);
+  DefaultValue<string16>::Set(string16());
+  DefaultValue<ValidityData>::Set(ValidityData());
+  DefaultValue<DialogSignedInState>::Set(REQUIRES_RESPONSE);
+  DefaultValue<gfx::Image>::Set(gfx::Image());
+  DefaultValue<SuggestionState>::Set(SuggestionState(string16(),
+                                                     gfx::Font::NORMAL,
+                                                     gfx::Image(),
+                                                     string16(),
+                                                     gfx::Image()));
 
   // SECTION_CC *must* have a CREDIT_CARD_VERIFICATION_CODE field.
   const DetailInput kCreditCardInputs[] = {
@@ -19,172 +36,28 @@
   };
   cc_default_inputs_.push_back(kCreditCardInputs[0]);
   ON_CALL(*this, RequestedFieldsForSection(SECTION_CC))
-      .WillByDefault(testing::ReturnRef(cc_default_inputs_));
+      .WillByDefault(ReturnRef(cc_default_inputs_));
+
+  ON_CALL(*this, GetDialogButtons())
+      .WillByDefault(Return(ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL));
+  ON_CALL(*this, LegalDocumentLinks()).WillByDefault(ReturnRef(range_));
 
   // Activate all sections but CC_BILLING - default for the real
   // controller implementation, too.
-  ON_CALL(*this, SectionIsActive(testing::_))
-      .WillByDefault(testing::Return(true));
+  ON_CALL(*this, SectionIsActive(_)).WillByDefault(Return(true));
   ON_CALL(*this, SectionIsActive(SECTION_CC_BILLING))
-      .WillByDefault(testing::Return(false));
+      .WillByDefault(Return(false));
 }
 
 MockAutofillDialogController::~MockAutofillDialogController() {
-  testing::DefaultValue<ValidityData>::Clear();
-  testing::DefaultValue<ui::ComboboxModel*>::Clear();
-  testing::DefaultValue<const DetailInputs&>::Clear();
-}
+  using testing::DefaultValue;
 
-string16 MockAutofillDialogController::DialogTitle() const {
-  return string16();
-}
-
-string16 MockAutofillDialogController::AccountChooserText() const {
-  return string16();
-}
-
-string16 MockAutofillDialogController::SignInLinkText() const {
-  return string16();
-}
-
-string16 MockAutofillDialogController::EditSuggestionText() const {
-  return string16();
-}
-
-string16 MockAutofillDialogController::CancelButtonText() const {
-  return string16();
-}
-
-string16 MockAutofillDialogController::ConfirmButtonText() const {
-  return string16();
-}
-
-string16 MockAutofillDialogController::SaveLocallyText() const {
-  return string16();
-}
-
-string16 MockAutofillDialogController::LegalDocumentsText() {
-  return string16();
-}
-
-DialogSignedInState MockAutofillDialogController::SignedInState() const {
-   return REQUIRES_RESPONSE;
-}
-
-bool MockAutofillDialogController::ShouldShowSpinner() const {
-  return false;
-}
-
-gfx::Image MockAutofillDialogController::AccountChooserImage() {
-  return gfx::Image();
-}
-
-bool MockAutofillDialogController::ShouldShowDetailArea() const {
-  return false;
-}
-
-bool MockAutofillDialogController::ShouldShowProgressBar() const {
-  return false;
-}
-
-int MockAutofillDialogController::GetDialogButtons() const {
-  return ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL;
-}
-
-bool MockAutofillDialogController::IsDialogButtonEnabled(
-    ui::DialogButton button) const {
-  return false;
-}
-
-DialogOverlayState MockAutofillDialogController::GetDialogOverlay() const {
-  return DialogOverlayState();
-}
-
-const std::vector<ui::Range>&
-    MockAutofillDialogController::LegalDocumentLinks() {
-  return range_;
-}
-
-string16 MockAutofillDialogController::LabelForSection(
-    DialogSection section) const {
-  return string16();
-}
-
-SuggestionState MockAutofillDialogController::SuggestionStateForSection(
-    DialogSection section) {
-  return SuggestionState(string16(),
-                         gfx::Font::NORMAL,
-                         gfx::Image(),
-                         string16(),
-                         gfx::Image());
-}
-
-void MockAutofillDialogController::EditClickedForSection(
-    DialogSection section) {}
-
-void MockAutofillDialogController::EditCancelledForSection(
-    DialogSection section) {}
-
-gfx::Image MockAutofillDialogController::IconForField(
-    AutofillFieldType type, const string16& user_input) const {
-   return gfx::Image();
-}
-
-string16 MockAutofillDialogController::InputValidityMessage(
-    DialogSection section,
-    AutofillFieldType type,
-    const string16& value) {
-  return string16();
-}
-
-void MockAutofillDialogController::UserEditedOrActivatedInput(
-    DialogSection section,
-    const DetailInput* input,
-    gfx::NativeView parent_view,
-    const gfx::Rect& content_bounds,
-    const string16& field_contents,
-    bool was_edit) {}
-
-bool MockAutofillDialogController::HandleKeyPressEventInInput(
-     const content::NativeWebKeyboardEvent& event) {
-  return false;
-}
-
-void MockAutofillDialogController::FocusMoved() {}
-
-gfx::Image MockAutofillDialogController::SplashPageImage() const {
-  return gfx::Image();
-}
-
-void MockAutofillDialogController::ViewClosed() {}
-
-std::vector<DialogNotification> MockAutofillDialogController::
-    CurrentNotifications() {
-  return std::vector<DialogNotification>();
-}
-
-std::vector<DialogAutocheckoutStep> MockAutofillDialogController::
-    CurrentAutocheckoutSteps() const {
-  return std::vector<DialogAutocheckoutStep>();
-}
-
-void MockAutofillDialogController::SignInLinkClicked() {}
-
-void MockAutofillDialogController::NotificationCheckboxStateChanged(
-    DialogNotification::Type type,
-    bool checked) {}
-
-void MockAutofillDialogController::LegalDocumentLinkClicked(
-    const ui::Range& range) {}
-
-void MockAutofillDialogController::OverlayButtonPressed() {}
-
-void MockAutofillDialogController::OnCancel() {}
-
-void MockAutofillDialogController::OnAccept() {}
-
-content::WebContents* MockAutofillDialogController::web_contents() {
-  return NULL;
+  DefaultValue<SuggestionState>::Clear();
+  DefaultValue<gfx::Image>::Clear();
+  DefaultValue<DialogSignedInState>::Clear();
+  DefaultValue<ValidityData>::Clear();
+  DefaultValue<string16>::Clear();
+  DefaultValue<const DetailInputs&>::Clear();
 }
 
 }  // namespace autofill
diff --git a/chrome/browser/ui/autofill/mock_autofill_dialog_controller.h b/chrome/browser/ui/autofill/mock_autofill_dialog_controller.h
index 61a25d3..511b14b 100644
--- a/chrome/browser/ui/autofill/mock_autofill_dialog_controller.h
+++ b/chrome/browser/ui/autofill/mock_autofill_dialog_controller.h
@@ -15,76 +15,65 @@
   MockAutofillDialogController();
   virtual ~MockAutofillDialogController();
 
-  virtual string16 DialogTitle() const OVERRIDE;
-  virtual string16 AccountChooserText() const OVERRIDE;
-  virtual string16 SignInLinkText() const OVERRIDE;
-  virtual string16 EditSuggestionText() const OVERRIDE;
-  virtual string16 CancelButtonText() const OVERRIDE;
-  virtual string16 ConfirmButtonText() const OVERRIDE;
-  virtual string16 SaveLocallyText() const OVERRIDE;
-  virtual string16 LegalDocumentsText() OVERRIDE;
-  virtual DialogSignedInState SignedInState() const OVERRIDE;
-  virtual bool ShouldShowSpinner() const OVERRIDE;
+  MOCK_CONST_METHOD0(DialogTitle, string16());
+  MOCK_CONST_METHOD0(AccountChooserText, string16());
+  MOCK_CONST_METHOD0(SignInLinkText, string16());
+  MOCK_CONST_METHOD0(EditSuggestionText, string16());
+  MOCK_CONST_METHOD0(CancelButtonText, string16());
+  MOCK_CONST_METHOD0(ConfirmButtonText, string16());
+  MOCK_CONST_METHOD0(SaveLocallyText, string16());
+  MOCK_METHOD0(LegalDocumentsText, string16());
+  MOCK_CONST_METHOD0(SignedInState, DialogSignedInState());
+  MOCK_CONST_METHOD0(ShouldShowSpinner, bool());
   MOCK_CONST_METHOD0(ShouldOfferToSaveInChrome, bool());
   MOCK_METHOD0(MenuModelForAccountChooser, ui::MenuModel*());
-  virtual gfx::Image AccountChooserImage() OVERRIDE;
-  virtual bool ShouldShowProgressBar() const OVERRIDE;
-  virtual int GetDialogButtons() const OVERRIDE;
-  virtual bool ShouldShowDetailArea() const OVERRIDE;
-  virtual bool IsDialogButtonEnabled(ui::DialogButton button) const OVERRIDE;
-  virtual DialogOverlayState GetDialogOverlay() const OVERRIDE;
-  virtual const std::vector<ui::Range>& LegalDocumentLinks() OVERRIDE;
+  MOCK_METHOD0(AccountChooserImage, gfx::Image());
+  MOCK_CONST_METHOD0(ShouldShowProgressBar, bool());
+  MOCK_CONST_METHOD0(GetDialogButtons, int());
+  MOCK_CONST_METHOD0(ShouldShowDetailArea, bool());
+  MOCK_CONST_METHOD1(IsDialogButtonEnabled, bool(ui::DialogButton button));
+  MOCK_CONST_METHOD0(GetDialogOverlay, DialogOverlayState());
+  MOCK_METHOD0(LegalDocumentLinks, const std::vector<ui::Range>&());
   MOCK_CONST_METHOD1(SectionIsActive, bool(DialogSection));
   MOCK_CONST_METHOD1(RequestedFieldsForSection,
                      const DetailInputs&(DialogSection));
   MOCK_METHOD1(ComboboxModelForAutofillType,
                ui::ComboboxModel*(AutofillFieldType));
   MOCK_METHOD1(MenuModelForSection, ui::MenuModel*(DialogSection));
-  virtual string16 LabelForSection(DialogSection section) const OVERRIDE;
-  virtual SuggestionState SuggestionStateForSection(
-      DialogSection section) OVERRIDE;
-  virtual void EditClickedForSection(DialogSection section) OVERRIDE;
-  virtual void EditCancelledForSection(DialogSection section) OVERRIDE;
-  virtual gfx::Image IconForField(AutofillFieldType type,
-                                  const string16& user_input) const OVERRIDE;
-  virtual string16 InputValidityMessage(
-      DialogSection section,
-      AutofillFieldType type,
-      const string16& value) OVERRIDE;
+  MOCK_CONST_METHOD1(LabelForSection, string16(DialogSection section));
+  MOCK_METHOD1(SuggestionStateForSection, SuggestionState(DialogSection));
+  MOCK_METHOD1(EditClickedForSection, void(DialogSection section));
+  MOCK_METHOD1(EditCancelledForSection, void(DialogSection section));
+  MOCK_CONST_METHOD2(IconForField,
+                     gfx::Image(AutofillFieldType, const string16&));
+  MOCK_METHOD3(InputValidityMessage,
+      string16(DialogSection, AutofillFieldType, const string16&));
   MOCK_METHOD3(InputsAreValid, ValidityData(DialogSection,
                                             const DetailOutputMap&,
                                             ValidationType));
-  virtual void UserEditedOrActivatedInput(DialogSection section,
-                                          const DetailInput* input,
-                                          gfx::NativeView parent_view,
-                                          const gfx::Rect& content_bounds,
-                                          const string16& field_contents,
-                                          bool was_edit) OVERRIDE;
-  virtual bool HandleKeyPressEventInInput(
-      const content::NativeWebKeyboardEvent& event) OVERRIDE;
-
-  virtual void FocusMoved() OVERRIDE;
-
-  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;
-
-  virtual void LegalDocumentLinkClicked(const ui::Range& range) OVERRIDE;
-  virtual void OverlayButtonPressed() OVERRIDE;
-  virtual void OnCancel() OVERRIDE;
-  virtual void OnAccept() OVERRIDE;
-
+  MOCK_METHOD6(UserEditedOrActivatedInput,void(DialogSection,
+                                               const DetailInput*,
+                                               gfx::NativeView,
+                                               const gfx::Rect&,
+                                               const string16&,
+                                               bool was_edit));
+  MOCK_METHOD1(HandleKeyPressEventInInput,
+               bool(const content::NativeWebKeyboardEvent& event));
+  MOCK_METHOD0(FocusMoved, void());
+  MOCK_CONST_METHOD0(SplashPageImage, gfx::Image());
+  MOCK_METHOD0(ViewClosed, void());
+  MOCK_METHOD0(CurrentNotifications,std::vector<DialogNotification>());
+  MOCK_CONST_METHOD0(CurrentAutocheckoutSteps,
+                     std::vector<DialogAutocheckoutStep>());
+  MOCK_METHOD0(SignInLinkClicked, void());
+  MOCK_METHOD2(NotificationCheckboxStateChanged,
+               void(DialogNotification::Type, bool));
+  MOCK_METHOD1(LegalDocumentLinkClicked, void(const ui::Range&));
+  MOCK_METHOD0(OverlayButtonPressed, void());
+  MOCK_METHOD0(OnCancel, bool());
+  MOCK_METHOD0(OnAccept, bool());
   MOCK_METHOD0(profile, Profile*());
-  virtual content::WebContents* web_contents() OVERRIDE;
+  MOCK_METHOD0(web_contents, content::WebContents*());
  private:
   DetailInputs default_inputs_;
   DetailInputs cc_default_inputs_;  // Default inputs for SECTION_CC.
diff --git a/chrome/browser/ui/autofill/tab_autofill_manager_delegate.cc b/chrome/browser/ui/autofill/tab_autofill_manager_delegate.cc
index ffb4546..44603d9 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/content/browser/autofill_driver_impl.h"
 #include "components/autofill/core/common/autofill_pref_names.h"
 #include "content/public/browser/navigation_details.h"
 #include "content/public/browser/navigation_entry.h"
@@ -167,6 +168,13 @@
   popup_controller_->Show(values, labels, icons, identifiers);
 }
 
+void TabAutofillManagerDelegate::UpdateAutofillPopupDataListValues(
+    const std::vector<base::string16>& values,
+    const std::vector<base::string16>& labels) {
+  if (popup_controller_.get())
+    popup_controller_->UpdateDataListValues(values, labels);
+}
+
 void TabAutofillManagerDelegate::HideAutofillPopup() {
   if (popup_controller_.get())
     popup_controller_->Hide();
@@ -196,17 +204,23 @@
 void TabAutofillManagerDelegate::DidNavigateMainFrame(
     const content::LoadCommittedDetails& details,
     const content::FrameNavigateParams& params) {
-  // A redirect immediately after a successful Autocheckout flow shouldn't hide
-  // the dialog.
-  bool was_redirect = details.entry &&
-      content::PageTransitionIsRedirect(details.entry->GetTransitionType());
-  if (dialog_controller_.get() &&
-      (dialog_controller_->dialog_type() == DIALOG_TYPE_REQUEST_AUTOCOMPLETE ||
-       (!dialog_controller_->AutocheckoutIsRunning() && !was_redirect))) {
-    HideRequestAutocompleteDialog();
-  }
 
   HideAutocheckoutBubble();
+
+  if (!dialog_controller_.get())
+    return;
+
+  // A redirect immediately after a successful Autocheckout flow shouldn't hide
+  // the dialog.
+  bool preserve_dialog = AutofillDriverImpl::FromWebContents(web_contents())->
+      autofill_manager()->autocheckout_manager()->should_preserve_dialog();
+  bool was_redirect = details.entry &&
+      content::PageTransitionIsRedirect(details.entry->GetTransitionType());
+
+  if (dialog_controller_->dialog_type() == DIALOG_TYPE_REQUEST_AUTOCOMPLETE ||
+      (!was_redirect && !preserve_dialog)) {
+    HideRequestAutocompleteDialog();
+  }
 }
 
 void TabAutofillManagerDelegate::WebContentsDestroyed(
diff --git a/chrome/browser/ui/autofill/tab_autofill_manager_delegate.h b/chrome/browser/ui/autofill/tab_autofill_manager_delegate.h
index 446721f..75879bd 100644
--- a/chrome/browser/ui/autofill/tab_autofill_manager_delegate.h
+++ b/chrome/browser/ui/autofill/tab_autofill_manager_delegate.h
@@ -69,6 +69,9 @@
       const std::vector<string16>& icons,
       const std::vector<int>& identifiers,
       base::WeakPtr<AutofillPopupDelegate> delegate) OVERRIDE;
+  virtual void UpdateAutofillPopupDataListValues(
+      const std::vector<base::string16>& values,
+      const std::vector<base::string16>& labels) OVERRIDE;
   virtual void HideAutofillPopup() OVERRIDE;
   virtual bool IsAutocompleteEnabled() OVERRIDE;
 
diff --git a/chrome/browser/ui/blocked_content/OWNERS b/chrome/browser/ui/blocked_content/OWNERS
new file mode 100644
index 0000000..8c37c31
--- /dev/null
+++ b/chrome/browser/ui/blocked_content/OWNERS
@@ -0,0 +1,2 @@
+bauerb@chromium.org
+jochen@chromium.org
diff --git a/chrome/browser/ui/blocked_content/popup_blocker_browsertest.cc b/chrome/browser/ui/blocked_content/popup_blocker_browsertest.cc
index 3c57f87..ddf8415 100644
--- a/chrome/browser/ui/blocked_content/popup_blocker_browsertest.cc
+++ b/chrome/browser/ui/blocked_content/popup_blocker_browsertest.cc
@@ -14,6 +14,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/search_engines/template_url_service_factory.h"
 #include "chrome/browser/ui/blocked_content/blocked_content_tab_helper.h"
+#include "chrome/browser/ui/blocked_content/popup_blocker_tab_helper.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/browser_finder.h"
@@ -210,10 +211,22 @@
   EXPECT_EQ(ASCIIToUTF16(search_string), model->CurrentMatch(NULL).contents);
 }
 
-IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest, BlockWebContentsCreation) {
-  CommandLine::ForCurrentProcess()->AppendSwitch(
-      switches::kEnableBetterPopupBlocking);
+class BetterPopupBlockerBrowserTest : public PopupBlockerBrowserTest {
+ public:
+  BetterPopupBlockerBrowserTest() {}
+  virtual ~BetterPopupBlockerBrowserTest() {}
 
+  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
+    PopupBlockerBrowserTest::SetUpCommandLine(command_line);
+    command_line->AppendSwitch(switches::kEnableBetterPopupBlocking);
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(BetterPopupBlockerBrowserTest);
+};
+
+IN_PROC_BROWSER_TEST_F(BetterPopupBlockerBrowserTest,
+                       BlockWebContentsCreation) {
   CountRenderViewHosts counter;
 
   ui_test_utils::NavigateToURL(browser(), GetTestURL());
@@ -230,11 +243,8 @@
   EXPECT_EQ(0, counter.GetRenderViewHostCreatedCount());
 }
 
-IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest,
+IN_PROC_BROWSER_TEST_F(BetterPopupBlockerBrowserTest,
                        PopupBlockedFakeClickOnAnchorNoTarget) {
-  CommandLine::ForCurrentProcess()->AppendSwitch(
-      switches::kEnableBetterPopupBlocking);
-
   GURL url(ui_test_utils::GetTestUrl(
       base::FilePath(kTestDir),
       base::FilePath(FILE_PATH_LITERAL("popup-fake-click-on-anchor2.html"))));
@@ -253,6 +263,21 @@
 
   // And no new RVH created.
   EXPECT_EQ(0, counter.GetRenderViewHostCreatedCount());
+
+  content::WindowedNotificationObserver observer(
+      chrome::NOTIFICATION_TAB_ADDED,
+      content::NotificationService::AllSources());
+
+  // Launch the blocked popup.
+  PopupBlockerTabHelper* popup_blocker_helper =
+      PopupBlockerTabHelper::FromWebContents(web_contents);
+  EXPECT_EQ(1u, popup_blocker_helper->GetBlockedPopupsCount());
+  IDMap<chrome::NavigateParams, IDMapOwnPointer>::const_iterator iter(
+      &popup_blocker_helper->GetBlockedPopupRequests());
+  ASSERT_FALSE(iter.IsAtEnd());
+  popup_blocker_helper->ShowBlockedPopup(iter.GetCurrentKey());
+
+  observer.Wait();
 }
 
 }  // namespace
diff --git a/chrome/browser/ui/blocked_content/popup_blocker_tab_helper.cc b/chrome/browser/ui/blocked_content/popup_blocker_tab_helper.cc
index a4ad316..41b36ff 100644
--- a/chrome/browser/ui/blocked_content/popup_blocker_tab_helper.cc
+++ b/chrome/browser/ui/blocked_content/popup_blocker_tab_helper.cc
@@ -90,7 +90,7 @@
   return blocked_popups_.size();
 }
 
-const IDMap<chrome::NavigateParams, IDMapOwnPointer>&
-PopupBlockerTabHelper::GetBlockedPopupRequests() const {
+IDMap<chrome::NavigateParams, IDMapOwnPointer>&
+PopupBlockerTabHelper::GetBlockedPopupRequests() {
   return blocked_popups_;
 }
diff --git a/chrome/browser/ui/blocked_content/popup_blocker_tab_helper.h b/chrome/browser/ui/blocked_content/popup_blocker_tab_helper.h
index 3383886..1526054 100644
--- a/chrome/browser/ui/blocked_content/popup_blocker_tab_helper.h
+++ b/chrome/browser/ui/blocked_content/popup_blocker_tab_helper.h
@@ -31,8 +31,8 @@
   size_t GetBlockedPopupsCount() const;
 
   // Returns the mapping from popup IDs to blocked popup requests.
-  const IDMap<chrome::NavigateParams, IDMapOwnPointer>&
-  GetBlockedPopupRequests() const;
+  IDMap<chrome::NavigateParams, IDMapOwnPointer>&
+  GetBlockedPopupRequests();
 
   // content::WebContentsObserver overrides:
   virtual void DidNavigateMainFrame(
diff --git a/chrome/browser/ui/bookmarks/bookmark_bubble_delegate.h b/chrome/browser/ui/bookmarks/bookmark_bubble_delegate.h
new file mode 100644
index 0000000..4927693
--- /dev/null
+++ b/chrome/browser/ui/bookmarks/bookmark_bubble_delegate.h
@@ -0,0 +1,14 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_BOOKMARKS_BOOKMARK_BUBBLE_DELEGATE_H_
+#define CHROME_BROWSER_UI_BOOKMARKS_BOOKMARK_BUBBLE_DELEGATE_H_
+
+class BookmarkBubbleDelegate {
+ public:
+  virtual ~BookmarkBubbleDelegate() {}
+  virtual void OnSignInLinkClicked() = 0;
+};
+
+#endif  // CHROME_BROWSER_UI_BOOKMARKS_BOOKMARK_BUBBLE_DELEGATE_H_
diff --git a/chrome/browser/ui/bookmarks/bookmark_bubble_sign_in_delegate.cc b/chrome/browser/ui/bookmarks/bookmark_bubble_sign_in_delegate.cc
new file mode 100644
index 0000000..9ac9c8c
--- /dev/null
+++ b/chrome/browser/ui/bookmarks/bookmark_bubble_sign_in_delegate.cc
@@ -0,0 +1,48 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/bookmarks/bookmark_bubble_sign_in_delegate.h"
+
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_finder.h"
+#include "chrome/browser/ui/browser_list.h"
+#include "chrome/browser/ui/browser_window.h"
+#include "chrome/browser/ui/chrome_pages.h"
+#include "chrome/browser/ui/sync/sync_promo_ui.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
+
+BookmarkBubbleSignInDelegate::BookmarkBubbleSignInDelegate(Browser* browser)
+    : browser_(browser),
+      profile_(browser->profile()),
+      desktop_type_(browser->host_desktop_type()) {
+  BrowserList::AddObserver(this);
+}
+
+BookmarkBubbleSignInDelegate::~BookmarkBubbleSignInDelegate() {
+  BrowserList::RemoveObserver(this);
+}
+
+void BookmarkBubbleSignInDelegate::OnSignInLinkClicked() {
+  EnsureBrowser();
+  chrome::ShowBrowserSignin(browser_, SyncPromoUI::SOURCE_BOOKMARK_BUBBLE);
+  DCHECK(!browser_->tab_strip_model()->empty());
+  browser_->window()->Show();
+}
+
+void BookmarkBubbleSignInDelegate::OnBrowserRemoved(Browser* browser) {
+  if (browser == browser_)
+    browser_ = NULL;
+}
+
+void BookmarkBubbleSignInDelegate::EnsureBrowser() {
+  if (!browser_) {
+    Profile* original_profile = profile_->GetOriginalProfile();
+    browser_ = chrome::FindLastActiveWithProfile(original_profile,
+                                                 desktop_type_);
+    if (!browser_) {
+      browser_ = new Browser(Browser::CreateParams(original_profile,
+                                                   desktop_type_));
+    }
+  }
+}
diff --git a/chrome/browser/ui/bookmarks/bookmark_bubble_sign_in_delegate.h b/chrome/browser/ui/bookmarks/bookmark_bubble_sign_in_delegate.h
new file mode 100644
index 0000000..88e3944
--- /dev/null
+++ b/chrome/browser/ui/bookmarks/bookmark_bubble_sign_in_delegate.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_UI_BOOKMARKS_BOOKMARK_BUBBLE_SIGN_IN_DELEGATE_H_
+#define CHROME_BROWSER_UI_BOOKMARKS_BOOKMARK_BUBBLE_SIGN_IN_DELEGATE_H_
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "chrome/browser/ui/bookmarks/bookmark_bubble_delegate.h"
+#include "chrome/browser/ui/browser_list_observer.h"
+#include "chrome/browser/ui/host_desktop.h"
+
+class Browser;
+class Profile;
+
+// Delegate of the bookmark bubble to load the sign in page in a browser
+// when the sign in link is clicked.
+class BookmarkBubbleSignInDelegate : public BookmarkBubbleDelegate,
+                                     public chrome::BrowserListObserver {
+ public:
+  explicit BookmarkBubbleSignInDelegate(Browser* browser);
+
+ private:
+  virtual ~BookmarkBubbleSignInDelegate();
+
+  // BookmarkBubbleDelegate:
+  virtual void OnSignInLinkClicked() OVERRIDE;
+
+  // chrome::BrowserListObserver:
+  virtual void OnBrowserRemoved(Browser* browser) OVERRIDE;
+
+  // Makes sure |browser_| points to a valid browser.
+  void EnsureBrowser();
+
+  // The browser in which the sign in page must be loaded.
+  Browser* browser_;
+
+  // The profile associated with |browser_|.
+  Profile* profile_;
+
+  // The host desktop of |browser_|.
+  chrome::HostDesktopType desktop_type_;
+
+  DISALLOW_COPY_AND_ASSIGN(BookmarkBubbleSignInDelegate);
+};
+
+#endif  // CHROME_BROWSER_UI_BOOKMARKS_BOOKMARK_BUBBLE_SIGN_IN_DELEGATE_H_
diff --git a/chrome/browser/ui/bookmarks/bookmark_bubble_sign_in_delegate_unittest.cc b/chrome/browser/ui/bookmarks/bookmark_bubble_sign_in_delegate_unittest.cc
new file mode 100644
index 0000000..f15b007
--- /dev/null
+++ b/chrome/browser/ui/bookmarks/bookmark_bubble_sign_in_delegate_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/ui/bookmarks/bookmark_bubble_sign_in_delegate.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "chrome/browser/ui/bookmarks/bookmark_bubble_delegate.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_list.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/test/base/browser_with_test_window_test.h"
+#include "ui/base/events/event_constants.h"
+#include "ui/base/range/range.h"
+
+typedef BrowserWithTestWindowTest BookmarkBubbleSignInDelegateTest;
+
+TEST_F(BookmarkBubbleSignInDelegateTest, OnSignInLinkClicked) {
+  int starting_tab_count = browser()->tab_strip_model()->count();
+
+  scoped_ptr<BookmarkBubbleDelegate> delegate;
+  delegate.reset(new BookmarkBubbleSignInDelegate(browser()));
+
+  delegate->OnSignInLinkClicked();
+
+  // A new tab should have been opened.
+  int tab_count = browser()->tab_strip_model()->count();
+  EXPECT_EQ(starting_tab_count + 1, tab_count);
+}
+
+// Verifies that the sign in page can be loaded in a different browser
+// if the provided browser is invalidated.
+TEST_F(BookmarkBubbleSignInDelegateTest, BrowserRemoved) {
+  // Create an extra browser.
+  scoped_ptr<BrowserWindow> extra_window;
+  extra_window.reset(CreateBrowserWindow());
+
+  Browser::CreateParams params(browser()->profile(),
+                               browser()->host_desktop_type());
+  params.window = extra_window.get();
+  scoped_ptr<Browser> extra_browser;
+  extra_browser.reset(new Browser(params));
+
+  int starting_tab_count = extra_browser->tab_strip_model()->count();
+
+  scoped_ptr<BookmarkBubbleDelegate> delegate;
+  delegate.reset(new BookmarkBubbleSignInDelegate(browser()));
+
+  BrowserList::SetLastActive(extra_browser.get());
+
+  browser()->tab_strip_model()->CloseAllTabs();
+  set_browser(NULL);
+
+  delegate->OnSignInLinkClicked();
+
+  // A new tab should have been opened in the extra browser.
+  int tab_count = extra_browser->tab_strip_model()->count();
+  EXPECT_EQ(starting_tab_count + 1, tab_count);
+
+  // Required to avoid a crash when the browser is deleted.
+  extra_browser->tab_strip_model()->CloseAllTabs();
+}
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc
index aa2e18f..bd0799f 100644
--- a/chrome/browser/ui/browser.cc
+++ b/chrome/browser/ui/browser.cc
@@ -89,6 +89,7 @@
 #include "chrome/browser/themes/theme_service_factory.h"
 #include "chrome/browser/ui/app_modal_dialogs/javascript_dialog_manager.h"
 #include "chrome/browser/ui/blocked_content/blocked_content_tab_helper.h"
+#include "chrome/browser/ui/blocked_content/popup_blocker_tab_helper.h"
 #include "chrome/browser/ui/bookmarks/bookmark_tab_helper.h"
 #include "chrome/browser/ui/browser_command_controller.h"
 #include "chrome/browser/ui/browser_commands.h"
@@ -165,10 +166,10 @@
 #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/common/content_restriction.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/common/page_zoom.h"
 #include "content/public/common/renderer_preferences.h"
+#include "content/public/common/webplugininfo.h"
 #include "extensions/common/constants.h"
 #include "grit/chromium_strings.h"
 #include "grit/generated_resources.h"
@@ -182,7 +183,6 @@
 #include "ui/base/window_open_disposition.h"
 #include "ui/gfx/point.h"
 #include "ui/shell_dialogs/selected_file_info.h"
-#include "webkit/plugins/webplugininfo.h"
 
 #if defined(OS_WIN)
 #include "base/win/metro.h"
@@ -678,9 +678,6 @@
   DCHECK(num_downloads_blocking);
   *num_downloads_blocking = 0;
 
-  if (IsAttemptingToCloseBrowser())
-    return DOWNLOAD_CLOSE_OK;
-
   // If we're not running a full browser process with a profile manager
   // (testing), it's ok to close the browser.
   if (!g_browser_process->profile_manager())
@@ -719,7 +716,8 @@
   // those downloads would be cancelled by our window (-> profile) close.
   DownloadService* download_service =
       DownloadServiceFactory::GetForProfile(profile());
-  if (profile_window_count == 0 && download_service->DownloadCount() > 0 &&
+  if ((profile_window_count == 0) &&
+      (download_service->DownloadCount() > 0) &&
       profile()->IsOffTheRecord()) {
     *num_downloads_blocking = download_service->DownloadCount();
     return DOWNLOAD_CLOSE_LAST_WINDOW_IN_INCOGNITO_PROFILE;
@@ -1272,26 +1270,21 @@
   nav_params.window_action = chrome::NavigateParams::SHOW_WINDOW;
   nav_params.user_gesture = params.user_gesture;
 
-  BlockedContentTabHelper* blocked_content_helper = NULL;
+  PopupBlockerTabHelper* popup_blocker_helper = NULL;
   if (source)
-    blocked_content_helper = BlockedContentTabHelper::FromWebContents(source);
+    popup_blocker_helper = PopupBlockerTabHelper::FromWebContents(source);
 
   if (CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kEnableBetterPopupBlocking) &&
-      blocked_content_helper) {
-
-    if (blocked_content_helper->all_contents_blocked()) {
-      // TODO(jochen): store information about the blocked pop-up in the
-      // helper.
-      return NULL;
-    }
+      popup_blocker_helper) {
 
     if ((params.disposition == NEW_POPUP ||
          params.disposition == NEW_FOREGROUND_TAB ||
          params.disposition == NEW_BACKGROUND_TAB) &&
         !params.user_gesture && !CommandLine::ForCurrentProcess()->HasSwitch(
                                     switches::kDisablePopupBlocking)) {
-      return NULL;
+      if (popup_blocker_helper->MaybeBlockPopup(nav_params))
+        return NULL;
     }
   }
 
@@ -1501,21 +1494,25 @@
     return true;
   }
 
-  BlockedContentTabHelper* blocked_content_helper =
-      BlockedContentTabHelper::FromWebContents(web_contents);
-  if (!blocked_content_helper)
+  PopupBlockerTabHelper* popup_blocker_helper =
+      PopupBlockerTabHelper::FromWebContents(web_contents);
+  if (!popup_blocker_helper)
     return true;
 
-  if (blocked_content_helper->all_contents_blocked()) {
-    // TODO(jochen): store information about the blocked pop-up in the helper.
-    return false;
-  }
-
   if ((disposition == NEW_POPUP || disposition == NEW_FOREGROUND_TAB ||
        disposition == NEW_BACKGROUND_TAB) && !user_gesture &&
       !CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kDisablePopupBlocking)) {
-    return false;
+    chrome::NavigateParams nav_params(
+        this, target_url, content::PAGE_TRANSITION_LINK);
+    // TODO(jochen): route missing information to here:
+    //   referrer, extra_headers, override_encoding
+    nav_params.source_contents = web_contents;
+    nav_params.tabstrip_add_types = TabStripModel::ADD_NONE;
+    nav_params.window_action = chrome::NavigateParams::SHOW_WINDOW;
+    nav_params.user_gesture = user_gesture;
+
+    return !popup_blocker_helper->MaybeBlockPopup(nav_params);
   }
 
   return true;
@@ -1545,10 +1542,6 @@
       content::Details<RetargetingDetails>(&details));
 }
 
-void Browser::ContentRestrictionsChanged(WebContents* source) {
-  command_controller_->ContentRestrictionsChanged();
-}
-
 void Browser::RendererUnresponsive(WebContents* source) {
   // Ignore hangs if a tab is blocked.
   int index = tab_strip_model_->GetIndexOfWebContents(source);
@@ -2211,8 +2204,7 @@
   // permission as that is checked in RenderMessageFilter when the CreateWindow
   // message is processed.
   const Extension* extension =
-      extensions_service->extensions()->GetHostedAppByURL(
-          ExtensionURLInfo(opener_url));
+      extensions_service->extensions()->GetHostedAppByURL(opener_url);
   if (!extension)
     return false;
 
diff --git a/chrome/browser/ui/browser.h b/chrome/browser/ui/browser.h
index af74dbb..61be1dd 100644
--- a/chrome/browser/ui/browser.h
+++ b/chrome/browser/ui/browser.h
@@ -573,8 +573,6 @@
                                   const string16& frame_name,
                                   const GURL& target_url,
                                   content::WebContents* new_contents) OVERRIDE;
-  virtual void ContentRestrictionsChanged(
-      content::WebContents* source) OVERRIDE;
   virtual void RendererUnresponsive(content::WebContents* source) OVERRIDE;
   virtual void RendererResponsive(content::WebContents* source) OVERRIDE;
   virtual void WorkerCrashed(content::WebContents* source) OVERRIDE;
diff --git a/chrome/browser/ui/browser_browsertest.cc b/chrome/browser/ui/browser_browsertest.cc
index 4603fbd..b2686af 100644
--- a/chrome/browser/ui/browser_browsertest.cc
+++ b/chrome/browser/ui/browser_browsertest.cc
@@ -86,6 +86,10 @@
 #include "chrome/browser/browser_process.h"
 #endif
 
+#if defined(OS_WIN) && defined(USE_ASH)
+#include "base/win/windows_version.h"
+#endif
+
 using content::InterstitialPage;
 using content::HostZoomMap;
 using content::NavigationController;
@@ -1949,6 +1953,12 @@
 };
 
 IN_PROC_BROWSER_TEST_F(AppModeTest, EnableAppModeTest) {
+#if defined(OS_WIN) && defined(USE_ASH)
+  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
+  if (base::win::GetVersion() >= base::win::VERSION_WIN8)
+    return;
+#endif
+
   // Test that an application browser window loads correctly.
 
   // Verify the browser is in application mode.
diff --git a/chrome/browser/ui/browser_command_controller.cc b/chrome/browser/ui/browser_command_controller.cc
index 54b8ecc..8726534 100644
--- a/chrome/browser/ui/browser_command_controller.cc
+++ b/chrome/browser/ui/browser_command_controller.cc
@@ -27,6 +27,7 @@
 #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/common/content_restriction.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/profiling.h"
 #include "content/public/browser/native_web_keyboard_event.h"
@@ -35,7 +36,6 @@
 #include "content/public/browser/user_metrics.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_observer.h"
-#include "content/public/common/content_restriction.h"
 #include "content/public/common/url_constants.h"
 #include "ui/base/keycodes/keyboard_codes.h"
 
@@ -1042,11 +1042,11 @@
   int restrictions = GetContentRestrictions(browser_);
 
   command_updater_.UpdateCommandEnabled(
-      IDC_COPY, !(restrictions & content::CONTENT_RESTRICTION_COPY));
+      IDC_COPY, !(restrictions & CONTENT_RESTRICTION_COPY));
   command_updater_.UpdateCommandEnabled(
-      IDC_CUT, !(restrictions & content::CONTENT_RESTRICTION_CUT));
+      IDC_CUT, !(restrictions & CONTENT_RESTRICTION_CUT));
   command_updater_.UpdateCommandEnabled(
-      IDC_PASTE, !(restrictions & content::CONTENT_RESTRICTION_PASTE));
+      IDC_PASTE, !(restrictions & CONTENT_RESTRICTION_PASTE));
   UpdateSaveAsState();
   UpdatePrintingState();
 }
diff --git a/chrome/browser/ui/browser_command_controller_browsertest.cc b/chrome/browser/ui/browser_command_controller_browsertest.cc
index 1f71986..9710148 100644
--- a/chrome/browser/ui/browser_command_controller_browsertest.cc
+++ b/chrome/browser/ui/browser_command_controller_browsertest.cc
@@ -22,7 +22,7 @@
   content::WebContents* web_contents =
       browser()->tab_strip_model()->GetActiveWebContents();
   MockTabModalConfirmDialogDelegate* delegate =
-      new MockTabModalConfirmDialogDelegate(web_contents, NULL);
+      new MockTabModalConfirmDialogDelegate(NULL);
   TabModalConfirmDialog::Create(delegate, web_contents);
   EXPECT_FALSE(chrome::IsCommandEnabled(browser(), IDC_FIND));
 
diff --git a/chrome/browser/ui/browser_commands.cc b/chrome/browser/ui/browser_commands.cc
index 22f6e1c..c083fba 100644
--- a/chrome/browser/ui/browser_commands.cc
+++ b/chrome/browser/ui/browser_commands.cc
@@ -50,12 +50,14 @@
 #include "chrome/browser/ui/fullscreen/fullscreen_controller.h"
 #include "chrome/browser/ui/omnibox/location_bar.h"
 #include "chrome/browser/ui/status_bubble.h"
+#include "chrome/browser/ui/tab_contents/core_tab_helper.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #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_switches.h"
 #include "chrome/common/chrome_version_info.h"
+#include "chrome/common/content_restriction.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"
@@ -67,7 +69,6 @@
 #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/common/content_restriction.h"
 #include "content/public/common/renderer_preferences.h"
 #include "content/public/common/url_constants.h"
 #include "content/public/common/url_utils.h"
@@ -242,16 +243,18 @@
   int content_restrictions = 0;
   WebContents* current_tab = browser->tab_strip_model()->GetActiveWebContents();
   if (current_tab) {
-    content_restrictions = current_tab->GetContentRestrictions();
+    CoreTabHelper* core_tab_helper =
+        CoreTabHelper::FromWebContents(current_tab);
+    content_restrictions = core_tab_helper->content_restrictions();
     NavigationEntry* active_entry =
         current_tab->GetController().GetActiveEntry();
     // See comment in UpdateCommandsForTabState about why we call url().
     if (!content::IsSavableURL(
             active_entry ? active_entry->GetURL() : GURL()) ||
         current_tab->ShowingInterstitialPage())
-      content_restrictions |= content::CONTENT_RESTRICTION_SAVE;
+      content_restrictions |= CONTENT_RESTRICTION_SAVE;
     if (current_tab->ShowingInterstitialPage())
-      content_restrictions |= content::CONTENT_RESTRICTION_PRINT;
+      content_restrictions |= CONTENT_RESTRICTION_PRINT;
   }
   return content_restrictions;
 }
@@ -694,7 +697,7 @@
     return false;
   }
   return !browser->is_devtools() &&
-      !(GetContentRestrictions(browser) & content::CONTENT_RESTRICTION_SAVE);
+      !(GetContentRestrictions(browser) & CONTENT_RESTRICTION_SAVE);
 }
 
 void ShowFindBar(Browser* browser) {
@@ -726,7 +729,7 @@
   // Do not print when a constrained window is showing. It's confusing.
   return browser->profile()->GetPrefs()->GetBoolean(prefs::kPrintingEnabled) &&
       !(IsShowingWebContentsModalDialog(browser) ||
-      GetContentRestrictions(browser) & content::CONTENT_RESTRICTION_PRINT);
+      GetContentRestrictions(browser) & CONTENT_RESTRICTION_PRINT);
 }
 
 void AdvancedPrint(Browser* browser) {
diff --git a/chrome/browser/ui/browser_commands_mac.cc b/chrome/browser/ui/browser_commands_mac.cc
index 3a18758..5b92019 100644
--- a/chrome/browser/ui/browser_commands_mac.cc
+++ b/chrome/browser/ui/browser_commands_mac.cc
@@ -4,16 +4,23 @@
 
 #include "chrome/browser/ui/browser_commands_mac.h"
 
+#include "base/command_line.h"
 #include "base/mac/mac_util.h"
 #include "chrome/browser/fullscreen.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/fullscreen/fullscreen_controller.h"
+#include "chrome/common/chrome_switches.h"
 
 namespace chrome {
 
 void ToggleFullscreenWithChromeOrFallback(Browser* browser) {
-  if (chrome::mac::SupportsSystemFullscreen())
+  // In simplified fullscreen mode, the "WithChrome" variant does not exist.
+  // Call into the standard cross-platform fullscreen method instead.
+  const CommandLine* command_line = CommandLine::ForCurrentProcess();
+  if (command_line->HasSwitch(switches::kEnableSimplifiedFullscreen))
+    ToggleFullscreenMode(browser);
+  else if (chrome::mac::SupportsSystemFullscreen())
     browser->fullscreen_controller()->ToggleFullscreenWithChrome();
   else
     ToggleFullscreenMode(browser);
diff --git a/chrome/browser/ui/browser_instant_controller.cc b/chrome/browser/ui/browser_instant_controller.cc
index 4adeb91..c36cad8 100644
--- a/chrome/browser/ui/browser_instant_controller.cc
+++ b/chrome/browser/ui/browser_instant_controller.cc
@@ -19,6 +19,7 @@
 #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/instant_ntp.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"
@@ -41,21 +42,22 @@
       instant_unload_handler_(browser) {
   profile_pref_registrar_.Init(profile()->GetPrefs());
   profile_pref_registrar_.Add(
-      prefs::kSearchSuggestEnabled,
-      base::Bind(&BrowserInstantController::ResetInstant,
-                 base::Unretained(this)));
-  profile_pref_registrar_.Add(
       prefs::kDefaultSearchProviderID,
       base::Bind(&BrowserInstantController::OnDefaultSearchProviderChanged,
                  base::Unretained(this)));
-  ResetInstant(std::string());
   browser_->search_model()->AddObserver(this);
-  net::NetworkChangeNotifier::AddNetworkChangeObserver(this);
+
+  InstantService* instant_service =
+      InstantServiceFactory::GetForProfile(profile());
+  instant_service->OnBrowserInstantControllerCreated();
 }
 
 BrowserInstantController::~BrowserInstantController() {
   browser_->search_model()->RemoveObserver(this);
-  net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
+
+  InstantService* instant_service =
+      InstantServiceFactory::GetForProfile(profile());
+  instant_service->OnBrowserInstantControllerDestroyed();
 }
 
 bool BrowserInstantController::MaybeSwapInInstantNTPContents(
@@ -71,7 +73,10 @@
     return false;
   }
 
-  scoped_ptr<content::WebContents> instant_ntp = instant_.ReleaseNTPContents();
+  InstantService* instant_service =
+      InstantServiceFactory::GetForProfile(profile());
+  scoped_ptr<content::WebContents> instant_ntp =
+      instant_service->ReleaseNTPContents();
   if (!instant_ntp)
     return false;
 
@@ -192,11 +197,6 @@
   instant_.ToggleVoiceSearch();
 }
 
-void BrowserInstantController::ResetInstant(const std::string& pref_name) {
-  if (chrome::ShouldPreloadInstantNTP(profile()))
-    instant_.ReloadStaleNTP();
-}
-
 ////////////////////////////////////////////////////////////////////////////////
 // BrowserInstantController, SearchModelObserver implementation:
 
@@ -223,15 +223,6 @@
     instant_.InstantSupportChanged(new_state.instant_support);
 }
 
-////////////////////////////////////////////////////////////////////////////////
-// BrowserInstantController, net::NetworkChangeNotifier::NetworkChangeObserver
-// implementation:
-
-void BrowserInstantController::OnNetworkChanged(
-    net::NetworkChangeNotifier::ConnectionType type) {
-  instant_.OnNetworkChanged(type);
-}
-
 void BrowserInstantController::OnDefaultSearchProviderChanged(
     const std::string& pref_name) {
   DCHECK_EQ(pref_name, std::string(prefs::kDefaultSearchProviderID));
@@ -269,5 +260,4 @@
     // renderer.
     contents->GetController().Reload(false);
   }
-  instant_.OnDefaultSearchProviderChanged();
 }
diff --git a/chrome/browser/ui/browser_instant_controller.h b/chrome/browser/ui/browser_instant_controller.h
index 6f2a025..0d99aaa 100644
--- a/chrome/browser/ui/browser_instant_controller.h
+++ b/chrome/browser/ui/browser_instant_controller.h
@@ -13,7 +13,6 @@
 #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 "net/base/network_change_notifier.h"
 #include "ui/base/window_open_disposition.h"
 
 class Browser;
@@ -28,9 +27,7 @@
 class Rect;
 }
 
-class BrowserInstantController
-    : public SearchModelObserver,
-      public net::NetworkChangeNotifier::NetworkChangeObserver {
+class BrowserInstantController : public SearchModelObserver {
  public:
   explicit BrowserInstantController(Browser* browser);
   virtual ~BrowserInstantController();
@@ -83,10 +80,6 @@
   void ToggleVoiceSearch();
 
  private:
-  // Sets the value of |instant_| based on value from profile. Invoked
-  // on pref change.
-  void ResetInstant(const std::string& pref_name);
-
   // Overridden from search::SearchModelObserver:
   virtual void ModelChanged(const SearchModel::State& old_state,
                             const SearchModel::State& new_state) OVERRIDE;
@@ -97,10 +90,6 @@
   // 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,
diff --git a/chrome/browser/ui/browser_navigator.cc b/chrome/browser/ui/browser_navigator.cc
index f71625e..5619112 100644
--- a/chrome/browser/ui/browser_navigator.cc
+++ b/chrome/browser/ui/browser_navigator.cc
@@ -247,7 +247,8 @@
   load_url_params.referrer = params->referrer;
   load_url_params.transition_type = params->transition;
   load_url_params.extra_headers = params->extra_headers;
-  load_url_params.is_cross_site_redirect = params->is_cross_site_redirect;
+  load_url_params.should_replace_current_entry =
+      params->should_replace_current_entry;
 
   if (params->transferred_global_request_id != GlobalRequestID()) {
     load_url_params.is_renderer_initiated = params->is_renderer_initiated;
@@ -392,7 +393,7 @@
       browser(a_browser),
       initiating_profile(NULL),
       host_desktop_type(GetHostDesktop(a_browser)),
-      is_cross_site_redirect(false) {
+      should_replace_current_entry(false) {
 }
 
 NavigateParams::NavigateParams(Browser* a_browser,
@@ -411,7 +412,7 @@
       browser(a_browser),
       initiating_profile(NULL),
       host_desktop_type(GetHostDesktop(a_browser)),
-      is_cross_site_redirect(false) {
+      should_replace_current_entry(false) {
 }
 
 NavigateParams::NavigateParams(Profile* a_profile,
@@ -432,7 +433,7 @@
       browser(NULL),
       initiating_profile(a_profile),
       host_desktop_type(chrome::GetActiveDesktop()),
-      is_cross_site_redirect(false) {
+      should_replace_current_entry(false) {
 }
 
 NavigateParams::~NavigateParams() {}
@@ -446,7 +447,8 @@
   nav_params->is_renderer_initiated = params.is_renderer_initiated;
   nav_params->transferred_global_request_id =
       params.transferred_global_request_id;
-  nav_params->is_cross_site_redirect = params.is_cross_site_redirect;
+  nav_params->should_replace_current_entry =
+      params.should_replace_current_entry;
 }
 
 void Navigate(NavigateParams* params) {
diff --git a/chrome/browser/ui/browser_navigator.h b/chrome/browser/ui/browser_navigator.h
index 5fbfb8b..1ba38fb 100644
--- a/chrome/browser/ui/browser_navigator.h
+++ b/chrome/browser/ui/browser_navigator.h
@@ -208,9 +208,9 @@
   // explicitly or inferred from an existing Browser instance.
   chrome::HostDesktopType host_desktop_type;
 
-  // Indicates whether this navigation involves a cross-process redirect,
-  // in which case it should replace the current navigation entry.
-  bool is_cross_site_redirect;
+  // Indicates whether this navigation  should replace the current
+  // navigation entry.
+  bool should_replace_current_entry;
 
  private:
   NavigateParams();
diff --git a/chrome/browser/ui/browser_tabrestore.cc b/chrome/browser/ui/browser_tabrestore.cc
index a949fc5..9bb737a 100644
--- a/chrome/browser/ui/browser_tabrestore.cc
+++ b/chrome/browser/ui/browser_tabrestore.cc
@@ -14,6 +14,7 @@
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "content/public/browser/navigation_controller.h"
 #include "content/public/browser/navigation_entry.h"
+#include "content/public/browser/session_storage_namespace.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_view.h"
 
@@ -44,6 +45,13 @@
     content::SessionStorageNamespace* session_storage_namespace,
     const std::string& user_agent_override) {
   GURL restore_url = navigations.at(selected_navigation).virtual_url();
+  // TODO(ajwong): Remove the temporary session_storage_namespace_map when
+  // we teach session restore to understand that one tab can have multiple
+  // SessionStorageNamespace objects. Also remove the
+  // session_storage_namespace.h include since we only need that to assign
+  // into the map.
+  content::SessionStorageNamespaceMap session_storage_namespace_map;
+  session_storage_namespace_map[std::string()] = session_storage_namespace;
   WebContents::CreateParams create_params(
       browser->profile(),
       tab_util::GetSiteInstanceForNewTab(browser->profile(), restore_url));
@@ -55,7 +63,7 @@
   }
   WebContents* web_contents = content::WebContents::CreateWithSessionStorage(
       create_params,
-      session_storage_namespace);
+      session_storage_namespace_map);
   extensions::TabHelper::CreateForWebContents(web_contents);
   extensions::TabHelper::FromWebContents(web_contents)->
       SetExtensionAppById(extension_app_id);
diff --git a/chrome/browser/ui/browser_tabstrip.cc b/chrome/browser/ui/browser_tabstrip.cc
index 9ffa615..38d33e5 100644
--- a/chrome/browser/ui/browser_tabstrip.cc
+++ b/chrome/browser/ui/browser_tabstrip.cc
@@ -76,7 +76,9 @@
     if ((disposition == NEW_POPUP || disposition == NEW_FOREGROUND_TAB ||
          disposition == NEW_BACKGROUND_TAB) && !user_gesture &&
         !CommandLine::ForCurrentProcess()->HasSwitch(
-            switches::kDisablePopupBlocking)) {
+            switches::kDisablePopupBlocking) &&
+        !CommandLine::ForCurrentProcess()->HasSwitch(
+            switches::kEnableBetterPopupBlocking)) {
       // Unrequested popups from normal pages are constrained unless they're in
       // the white list.  The popup owner will handle checking this.
       source_blocked_content->AddPopup(
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_details_container.h b/chrome/browser/ui/cocoa/autofill/autofill_details_container.h
index 5748080..9602169 100644
--- a/chrome/browser/ui/cocoa/autofill/autofill_details_container.h
+++ b/chrome/browser/ui/cocoa/autofill/autofill_details_container.h
@@ -24,6 +24,9 @@
     : NSViewController<AutofillLayout,
                        AutofillValidationDisplay> {
  @private
+  // Scroll view containing all detail sections.
+  base::scoped_nsobject<NSScrollView> scrollView_;
+
   // The individual detail sections.
   base::scoped_nsobject<NSMutableArray> details_;
 
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_details_container.mm b/chrome/browser/ui/cocoa/autofill/autofill_details_container.mm
index f2ce365..1b0de2c 100644
--- a/chrome/browser/ui/cocoa/autofill/autofill_details_container.mm
+++ b/chrome/browser/ui/cocoa/autofill/autofill_details_container.mm
@@ -50,9 +50,17 @@
   [self addSection:autofill::SECTION_CC_BILLING];
   [self addSection:autofill::SECTION_SHIPPING];
 
-  [self setView:[[NSView alloc] init]];
+  scrollView_.reset([[NSScrollView alloc] initWithFrame:NSZeroRect]);
+  [scrollView_ setHasVerticalScroller:YES];
+  [scrollView_ setHasHorizontalScroller:NO];
+  [scrollView_ setBorderType:NSNoBorder];
+  [scrollView_ setAutohidesScrollers:YES];
+  [self setView:scrollView_];
+
+  [scrollView_ setDocumentView:[[NSView alloc] initWithFrame:NSZeroRect]];
+
   for (AutofillSectionContainer* container in details_.get())
-    [[self view] addSubview:[container view]];
+    [[scrollView_ documentView] addSubview:[container view]];
 
   infoBubble_.reset([[InfoBubbleView alloc] initWithFrame:NSZeroRect]);
   [infoBubble_ setBackgroundColor:
@@ -67,7 +75,7 @@
   [label setDrawsBackground:NO];
   [infoBubble_ addSubview:label];
 
-  [[self view] addSubview:infoBubble_];
+  [[scrollView_ documentView] addSubview:infoBubble_];
 
   [self performLayout];
 }
@@ -93,7 +101,7 @@
     }
   }
 
-  [[self view] setFrameSize:[self preferredSize]];
+  [[scrollView_ documentView] setFrameSize:[self preferredSize]];
 }
 
 - (AutofillSectionContainer*)sectionForId:(autofill::DialogSection)section {
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 e003752..2f4d176 100644
--- a/chrome/browser/ui/cocoa/autofill/autofill_details_container_unittest.mm
+++ b/chrome/browser/ui/cocoa/autofill/autofill_details_container_unittest.mm
@@ -32,7 +32,10 @@
 TEST_VIEW(AutofillDetailsContainerTest, [container_ view])
 
 TEST_F(AutofillDetailsContainerTest, BasicProperties) {
+  EXPECT_TRUE([[container_ view] isKindOfClass:[NSScrollView class]]);
   EXPECT_GT([[[container_ view] subviews] count], 0U);
+
+  [[container_ view] setFrameSize:[container_ preferredSize]];
   EXPECT_GT(NSHeight([[container_ view] frame]), 0);
   EXPECT_GT(NSWidth([[container_ view] frame]), 0);
 }
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_dialog_cocoa.mm b/chrome/browser/ui/cocoa/autofill/autofill_dialog_cocoa.mm
index 6ac323b..8e59102 100644
--- a/chrome/browser/ui/cocoa/autofill/autofill_dialog_cocoa.mm
+++ b/chrome/browser/ui/cocoa/autofill/autofill_dialog_cocoa.mm
@@ -12,12 +12,15 @@
 #include "chrome/browser/ui/chrome_style.h"
 #import "chrome/browser/ui/cocoa/autofill/autofill_account_chooser.h"
 #import "chrome/browser/ui/cocoa/autofill/autofill_details_container.h"
+#include "chrome/browser/ui/cocoa/autofill/autofill_dialog_constants.h"
 #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"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_view.h"
 #import "ui/base/cocoa/flipped_view.h"
 #include "ui/base/cocoa/window_size_constants.h"
 
@@ -54,6 +57,7 @@
           initWithCustomWindow:[sheet_controller_ window]]);
   constrained_window_.reset(
       new ConstrainedWindowMac(this, controller_->web_contents(), sheet));
+  constrained_window_->SetPreventCloseOnLoadStart(true);
 }
 
 void AutofillDialogCocoa::Hide() {
@@ -180,6 +184,13 @@
 
 #pragma mark Window Controller
 
+@interface AutofillDialogWindowController ()
+
+// Notification that the WebContent's view frame has changed.
+- (void)onContentViewFrameDidChange:(NSNotification*)notification;
+
+@end
+
 @implementation AutofillDialogWindowController
 
 - (id)initWithWebContents:(content::WebContents*)webContents
@@ -235,10 +246,29 @@
                                chrome_style::kClientBottomPadding +
                                chrome_style::kTitleTopPadding;
     [self performLayout];
+
+    // Resizing the browser causes the ConstrainedWindow to move.
+    // Observe that to allow resizes based on browser size.
+    NSView* contentView = [[self window] contentView];
+    [contentView setPostsFrameChangedNotifications:YES];
+    [[NSNotificationCenter defaultCenter]
+        addObserver:self
+           selector:@selector(onContentViewFrameDidChange:)
+               name:NSWindowDidMoveNotification
+             object:[self window]];
   }
   return self;
 }
 
+- (void)dealloc {
+  [[NSNotificationCenter defaultCenter] removeObserver:self];
+  [super dealloc];
+}
+
+- (void)onContentViewFrameDidChange:(NSNotification*)notification {
+  [self performLayout];
+}
+
 - (void)requestRelayout {
   [self performLayout];
 }
@@ -252,10 +282,21 @@
   NSSize headerSize = NSMakeSize(contentSize.width, kAccountChooserHeight);
   NSSize size = NSMakeSize(
       std::max(contentSize.width, headerSize.width),
-      contentSize.height + headerSize.height + kRelatedControlVerticalSpacing);
+      contentSize.height + headerSize.height + kDetailTopPadding);
   size.width += 2 * chrome_style::kHorizontalPadding;
   size.height += chrome_style::kClientBottomPadding +
                  chrome_style::kTitleTopPadding;
+
+  // Show as much of the main view as is possible without going past the
+  // bottom of the browser window.
+  NSRect dialogFrameRect = [[self window] frame];
+  NSRect browserFrameRect =
+      [webContents_->GetView()->GetTopLevelNativeWindow() frame];
+  dialogFrameRect.size.height =
+      NSMaxY(dialogFrameRect) - NSMinY(browserFrameRect);
+  dialogFrameRect = [[self window] contentRectForFrameRect:dialogFrameRect];
+  size.height = std::min(NSHeight(dialogFrameRect), size.height);
+
   return size;
 }
 
@@ -268,9 +309,11 @@
   clientRect.size.height -= chrome_style::kTitleTopPadding +
                             chrome_style::kClientBottomPadding;
 
-  NSRect headerRect, mainRect;
+  NSRect headerRect, mainRect, dummyRect;
   NSDivideRect(clientRect, &headerRect, &mainRect,
                kAccountChooserHeight, NSMinYEdge);
+  NSDivideRect(mainRect, &dummyRect, &mainRect,
+               kDetailTopPadding, NSMinYEdge);
 
   [accountChooser_ setFrame:headerRect];
   if ([[signInContainer_ view] isHidden]) {
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_dialog_constants.h b/chrome/browser/ui/cocoa/autofill/autofill_dialog_constants.h
index b5d1ba3..98614e9 100644
--- a/chrome/browser/ui/cocoa/autofill/autofill_dialog_constants.h
+++ b/chrome/browser/ui/cocoa/autofill/autofill_dialog_constants.h
@@ -25,6 +25,12 @@
 // Vertical spacing between legal text and details section.
 const int kVerticalSpacing = 8;
 
+// Padding between top bar and details section.
+const int kDetailTopPadding = 20;
+
+// Padding between the bottom of the details section and the button strip.
+const int kDetailBottomPadding = 30;
+
 }  // namespace
 
 #endif  // CHROME_BROWSER_UI_COCOA_AUTOFILL_AUTOFILL_DIALOG_CONSTANTS__H_
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_main_container.mm b/chrome/browser/ui/cocoa/autofill/autofill_main_container.mm
index 4a9492a..7467810 100644
--- a/chrome/browser/ui/cocoa/autofill/autofill_main_container.mm
+++ b/chrome/browser/ui/cocoa/autofill/autofill_main_container.mm
@@ -104,6 +104,7 @@
 
   NSSize size = NSMakeSize(std::max(buttonSize.width, detailsSize.width),
                            buttonSize.height + detailsSize.height);
+  size.height += kDetailBottomPadding;
 
   if (![legalDocumentsView_ isHidden]) {
     NSSize legalDocumentSize =
@@ -118,12 +119,12 @@
 }
 
 - (void)performLayout {
-  NSSize preferredContainerSize = [self preferredSize];
+  NSRect bounds = [[self view] bounds];
 
   CGFloat currentY = 0.0;
   if (![legalDocumentsView_ isHidden]) {
     [legalDocumentsView_ setFrameSize:
-        [self preferredLegalDocumentSizeForWidth:preferredContainerSize.width]];
+        [self preferredLegalDocumentSizeForWidth:NSWidth(bounds)]];
     currentY = NSMaxY([legalDocumentsView_ frame]) + kVerticalSpacing;
   }
 
@@ -135,15 +136,23 @@
   checkboxFrame.origin.y = NSMidY(buttonFrame) - NSHeight(checkboxFrame) / 2.0;
   [saveInChromeCheckbox_ setFrameOrigin:checkboxFrame.origin];
 
-  [detailsContainer_ performLayout];
-  NSRect containerFrame = [[detailsContainer_ view] frame];
-  containerFrame.origin.y = NSMaxY(buttonFrame);
-  [[detailsContainer_ view] setFrameOrigin:containerFrame.origin];
+  currentY = NSMaxY(buttonFrame) + kDetailBottomPadding;
 
-  NSRect notificationFrame;
-  notificationFrame.origin = NSMakePoint(0, NSMaxY(containerFrame));
+  NSRect notificationFrame = NSZeroRect;
   notificationFrame.size = [notificationContainer_ preferredSizeForWidth:
-      preferredContainerSize.width];
+      NSWidth(bounds)];
+
+  // Buttons/checkbox/legal take up lower part of view, notifications the
+  // upper part. Adjust the detailsContainer to take up the remainder.
+  CGFloat remainingHeight =
+      NSHeight(bounds) - currentY - NSHeight(notificationFrame);
+  NSRect containerFrame =
+      NSMakeRect(0, currentY, NSWidth(bounds), remainingHeight);
+  [[detailsContainer_ view] setFrame:containerFrame];
+  [detailsContainer_ performLayout];
+
+  notificationFrame.origin =
+      NSMakePoint(0, NSMaxY(containerFrame) + kDetailTopPadding);
   [[notificationContainer_ view] setFrame:notificationFrame];
   [notificationContainer_ performLayout];
 }
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 66ca163..4fd79fb 100644
--- a/chrome/browser/ui/cocoa/autofill/autofill_main_container_unittest.mm
+++ b/chrome/browser/ui/cocoa/autofill/autofill_main_container_unittest.mm
@@ -42,7 +42,9 @@
   EXPECT_EQ(5U, [[[container_ view] subviews] count]);
   for (NSView* view in [[container_ view] subviews]) {
     NSArray* subviews = [view subviews];
-    if ([subviews count] == 2) {
+    if ([view isKindOfClass:[NSScrollView class]]) {
+      hasDetailsContainer = true;
+    } else if ([subviews count] == 2) {
       EXPECT_TRUE(
           [[subviews objectAtIndex:0] isKindOfClass:[NSButton class]]);
       EXPECT_TRUE(
@@ -50,10 +52,6 @@
       hasButtons = true;
     } else if ([view isKindOfClass:[NSTextView class]]) {
       hasTextView = true;
-    } else if ([subviews count] > 0 &&
-               [[subviews objectAtIndex:0] isKindOfClass:
-                   [AutofillSectionView class]]) {
-      hasDetailsContainer = true;
     } else if ([view isKindOfClass:[NSButton class]] &&
                view == [container_ saveInChromeCheckboxForTesting]) {
       hasCheckbox = true;
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 096e376..3a7cef4 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_toolbar_view.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_toolbar_view.mm
@@ -46,7 +46,8 @@
       [controller_ isAnimatingFromState:BookmarkBar::DETACHED]) {
     [self drawAsDetachedBubble];
   } else {
-    NSPoint phase = [[self window] themePatternPhase];
+    NSPoint phase = [[self window]
+        themePatternPhaseForAlignment:THEME_PATTERN_ALIGN_WITH_TAB_STRIP];
     [[NSGraphicsContext currentContext] cr_setPatternPhase:phase forView:self];
     [self drawBackgroundWithOpaque:YES];
   }
@@ -76,7 +77,9 @@
     CGContextRef cgContext = static_cast<CGContextRef>([context graphicsPort]);
     CGContextSetAlpha(cgContext, 1 - morph);
     CGContextBeginTransparencyLayer(cgContext, NULL);
-    [context cr_setPatternPhase:[[self window] themePatternPhase] forView:self];
+    NSPoint phase = [[self window]
+        themePatternPhaseForAlignment:THEME_PATTERN_ALIGN_WITH_TAB_STRIP];
+    [context cr_setPatternPhase:phase forView:self];
     [self drawBackgroundWithOpaque:YES];
     CGContextEndTransparencyLayer(cgContext);
   }
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bubble_controller.h b/chrome/browser/ui/cocoa/bookmarks/bookmark_bubble_controller.h
index c28fd50..3375361 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_bubble_controller.h
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bubble_controller.h
@@ -4,6 +4,7 @@
 
 #import <Cocoa/Cocoa.h>
 
+#include "base/mac/scoped_nsobject.h"
 #include "base/memory/scoped_ptr.h"
 #import "chrome/browser/ui/cocoa/base_bubble_controller.h"
 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_model_observer_for_cocoa.h"
@@ -11,6 +12,7 @@
 class BookmarkModel;
 class BookmarkNode;
 @class BookmarkBubbleController;
+@class BookmarkSyncPromoController;
 
 // Controller for the bookmark bubble.  The bookmark bubble is a
 // bubble that pops up when clicking on the STAR next to the URL to
@@ -30,9 +32,13 @@
   // Ping me when the bookmark model changes out from under us.
   scoped_ptr<BookmarkModelObserverForCocoa> bookmarkObserver_;
 
+  // Sync promo controller, if the sync promo is displayed.
+  base::scoped_nsobject<BookmarkSyncPromoController> syncPromoController_;
+
   IBOutlet NSTextField* bigTitle_;   // "Bookmark" or "Bookmark Added!"
   IBOutlet NSTextField* nameTextField_;
   IBOutlet NSPopUpButton* folderPopUpButton_;
+  IBOutlet NSView* syncPromoPlaceholder_;
 }
 
 @property(readonly, nonatomic) const BookmarkNode* node;
@@ -62,6 +68,9 @@
 
 // Exposed only for unit testing.
 @interface BookmarkBubbleController (ExposedForUnitTesting)
+
+@property(nonatomic, readonly) NSView* syncPromoPlaceholder;
+
 - (void)addFolderNodes:(const BookmarkNode*)parent
          toPopUpButton:(NSPopUpButton*)button
            indentation:(int)indentation;
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bubble_controller.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_bubble_controller.mm
index b851bad..3886719 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_bubble_controller.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bubble_controller.mm
@@ -4,14 +4,20 @@
 
 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bubble_controller.h"
 
+#include "base/command_line.h"
 #include "base/mac/bundle_locations.h"
 #include "base/mac/mac_util.h"
 #include "base/strings/sys_string_conversions.h"
 #include "chrome/browser/bookmarks/bookmark_model.h"
 #include "chrome/browser/bookmarks/bookmark_utils.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_finder.h"
 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_button.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_sync_promo_controller.h"
 #import "chrome/browser/ui/cocoa/browser_window_controller.h"
 #import "chrome/browser/ui/cocoa/info_bubble_view.h"
+#include "chrome/browser/ui/sync/sync_promo_ui.h"
+#include "chrome/common/chrome_switches.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
 #include "content/public/browser/notification_service.h"
@@ -67,6 +73,32 @@
   [super awakeFromNib];
 
   [[nameTextField_ cell] setUsesSingleLineMode:YES];
+
+  Browser* browser = chrome::FindBrowserWithWindow(self.parentWindow);
+  if (SyncPromoUI::ShouldShowSyncPromo(browser->profile()) &&
+      CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kEnableBookmarkSyncPromo)) {
+    syncPromoController_.reset(
+        [[BookmarkSyncPromoController alloc] initWithBrowser:browser]);
+    [syncPromoPlaceholder_ addSubview:[syncPromoController_ view]];
+
+    // Resize the sync promo and its placeholder.
+    NSRect syncPromoPlaceholderFrame = [syncPromoPlaceholder_ frame];
+    CGFloat syncPromoHeight = [syncPromoController_
+        preferredHeightForWidth:syncPromoPlaceholderFrame.size.width];
+    syncPromoPlaceholderFrame.size.height = syncPromoHeight;
+
+    [syncPromoPlaceholder_ setFrame:syncPromoPlaceholderFrame];
+    [[syncPromoController_ view] setFrame:syncPromoPlaceholderFrame];
+
+    // Adjust the height of the bubble so that the sync promo fits in it,
+    // except for its bottom border. The xib file hides the left and right
+    // borders of the sync promo.
+    NSRect bubbleFrame = [[self window] frame];
+    bubbleFrame.size.height +=
+        syncPromoHeight - [syncPromoController_ borderWidth];
+    [[self window] setFrame:bubbleFrame display:YES];
+  }
 }
 
 // If this is a new bookmark somewhere visible (e.g. on the bookmark
@@ -318,6 +350,10 @@
 
 @implementation BookmarkBubbleController (ExposedForUnitTesting)
 
+- (NSView*)syncPromoPlaceholder {
+  return syncPromoPlaceholder_;
+}
+
 + (NSString*)chooseAnotherFolderString {
   return l10n_util::GetNSStringWithFixup(
       IDS_BOOKMARK_BUBBLE_CHOOSER_ANOTHER_FOLDER);
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 1405f7c..bd8e4ff 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_bubble_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bubble_controller_unittest.mm
@@ -5,14 +5,20 @@
 #import <Cocoa/Cocoa.h>
 
 #include "base/basictypes.h"
+#include "base/command_line.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"
+#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/browser_window.h"
 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bubble_controller.h"
 #include "chrome/browser/ui/cocoa/browser_window_controller.h"
 #include "chrome/browser/ui/cocoa/cocoa_profile_test.h"
 #import "chrome/browser/ui/cocoa/info_bubble_window.h"
+#include "chrome/common/chrome_switches.h"
 #include "content/public/browser/notification_service.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #import "testing/gtest_mac.h"
@@ -57,6 +63,9 @@
 
 namespace {
 
+// URL of the test bookmark.
+const char kTestBookmarkURL[] = "http://www.google.com";
+
 class BookmarkBubbleControllerTest : public CocoaProfileTest {
  public:
   static int edits_;
@@ -66,7 +75,13 @@
     edits_ = 0;
   }
 
-  virtual void TearDown() {
+  virtual void SetUp() OVERRIDE {
+    CocoaProfileTest::SetUp();
+    CommandLine* command_line = CommandLine::ForCurrentProcess();
+    command_line->AppendSwitch(switches::kEnableBookmarkSyncPromo);
+  }
+
+  virtual void TearDown() OVERRIDE {
     [controller_ close];
     CocoaProfileTest::TearDown();
   }
@@ -79,11 +94,10 @@
       controller_ = nil;
     }
     controller_ = [[BookmarkBubbleController alloc]
-                      initWithParentWindow:test_window()
-                                     model:BookmarkModelFactory::GetForProfile(
-                                         profile())
-                                      node:node
-                         alreadyBookmarked:YES];
+        initWithParentWindow:browser()->window()->GetNativeWindow()
+                       model:BookmarkModelFactory::GetForProfile(profile())
+                        node:node
+           alreadyBookmarked:YES];
     EXPECT_TRUE([controller_ window]);
     // The window must be gone or we'll fail a unit test with windows left open.
     [static_cast<InfoBubbleWindow*>([controller_ window])
@@ -96,6 +110,14 @@
     return BookmarkModelFactory::GetForProfile(profile());
   }
 
+  const BookmarkNode* CreateTestBookmark() {
+    BookmarkModel* model = GetBookmarkModel();
+    return model->AddURL(model->bookmark_bar_node(),
+                         0,
+                         ASCIIToUTF16("Bookie markie title"),
+                         GURL(kTestBookmarkURL));
+  }
+
   bool IsWindowClosing() {
     return [static_cast<InfoBubbleWindow*>([controller_ window]) isClosing];
   }
@@ -107,32 +129,24 @@
 // Confirm basics about the bubble window (e.g. that it is inside the
 // parent window)
 TEST_F(BookmarkBubbleControllerTest, TestBubbleWindow) {
-  BookmarkModel* model = GetBookmarkModel();
-  const BookmarkNode* node = model->AddURL(model->bookmark_bar_node(),
-                                           0,
-                                           ASCIIToUTF16("Bookie markie title"),
-                                           GURL("http://www.google.com"));
+  const BookmarkNode* node = CreateTestBookmark();
   BookmarkBubbleController* controller = ControllerForNode(node);
   EXPECT_TRUE(controller);
   NSWindow* window = [controller window];
   EXPECT_TRUE(window);
-  EXPECT_TRUE(NSContainsRect([test_window() frame],
+  EXPECT_TRUE(NSContainsRect([browser()->window()->GetNativeWindow() frame],
                              [window frame]));
 }
 
 // Test that we can handle closing the parent window
 TEST_F(BookmarkBubbleControllerTest, TestClosingParentWindow) {
-  BookmarkModel* model = GetBookmarkModel();
-  const BookmarkNode* node = model->AddURL(model->bookmark_bar_node(),
-                                           0,
-                                           ASCIIToUTF16("Bookie markie title"),
-                                           GURL("http://www.google.com"));
+  const BookmarkNode* node = CreateTestBookmark();
   BookmarkBubbleController* controller = ControllerForNode(node);
   EXPECT_TRUE(controller);
   NSWindow* window = [controller window];
   EXPECT_TRUE(window);
   base::mac::ScopedNSAutoreleasePool pool;
-  [test_window() performClose:NSApp];
+  [browser()->window()->GetNativeWindow() performClose:NSApp];
 }
 
 
@@ -155,10 +169,10 @@
   const BookmarkNode* node4 = model->AddFolder(node2, 0, ASCIIToUTF16("sub"));
   EXPECT_TRUE(node4);
   const BookmarkNode* node5 = model->AddURL(node1, 0, ASCIIToUTF16("title1"),
-                                            GURL("http://www.google.com"));
+                                            GURL(kTestBookmarkURL));
   EXPECT_TRUE(node5);
   const BookmarkNode* node6 = model->AddURL(node3, 0, ASCIIToUTF16("title2"),
-                                            GURL("http://www.google.com"));
+                                            GURL(kTestBookmarkURL));
   EXPECT_TRUE(node6);
   const BookmarkNode* node7 = model->AddURL(
       node4, 0, ASCIIToUTF16("title3"), GURL("http://www.google.com/reader"));
@@ -204,7 +218,7 @@
                                                ASCIIToUTF16("three"));
   EXPECT_TRUE(node3);
   const BookmarkNode* node2_1 = model->AddURL(node2, 0, ASCIIToUTF16("title1"),
-                                              GURL("http://www.google.com"));
+                                              GURL(kTestBookmarkURL));
   EXPECT_TRUE(node2_1);
 
   BookmarkBubbleController* controller = ControllerForNode(node1);
@@ -228,11 +242,7 @@
 
 // Click on edit; bubble gets closed.
 TEST_F(BookmarkBubbleControllerTest, TestEdit) {
-  BookmarkModel* model = GetBookmarkModel();
-  const BookmarkNode* node = model->AddURL(model->bookmark_bar_node(),
-                                           0,
-                                           ASCIIToUTF16("Bookie markie title"),
-                                           GURL("http://www.google.com"));
+  const BookmarkNode* node = CreateTestBookmark();
   BookmarkBubbleController* controller = ControllerForNode(node);
   EXPECT_TRUE(controller);
 
@@ -246,10 +256,7 @@
 // CallClose; bubble gets closed.
 // Also confirm pulse notifications get sent.
 TEST_F(BookmarkBubbleControllerTest, TestClose) {
-    BookmarkModel* model = GetBookmarkModel();
-    const BookmarkNode* node = model->AddURL(
-        model->bookmark_bar_node(), 0, ASCIIToUTF16("Bookie markie title"),
-        GURL("http://www.google.com"));
+  const BookmarkNode* node = CreateTestBookmark();
   EXPECT_EQ(edits_, 0);
 
   base::scoped_nsobject<BookmarkPulseObserver> observer(
@@ -274,7 +281,7 @@
   const BookmarkNode* node = model->AddURL(bookmarkBarNode,
                                            0,
                                            ASCIIToUTF16("short-title"),
-                                           GURL("http://www.google.com"));
+                                           GURL(kTestBookmarkURL));
   const BookmarkNode* grandma = model->AddFolder(bookmarkBarNode, 0,
                                                  ASCIIToUTF16("grandma"));
   EXPECT_TRUE(grandma);
@@ -304,7 +311,7 @@
     const BookmarkNode* node = model->AddURL(bookmarkBarNode,
                                              0,
                                              ASCIIToUTF16("short-title"),
-                                             GURL("http://www.google.com"));
+                                             GURL(kTestBookmarkURL));
     EXPECT_TRUE(node);
     const BookmarkNode* folder = model->AddFolder(bookmarkBarNode, 0,
                                                  ASCIIToUTF16("NAME"));
@@ -353,28 +360,24 @@
 
 // Click the "remove" button
 TEST_F(BookmarkBubbleControllerTest, TestRemove) {
-  BookmarkModel* model = GetBookmarkModel();
-  GURL gurl("http://www.google.com");
-  const BookmarkNode* node = model->AddURL(model->bookmark_bar_node(),
-                                           0,
-                                           ASCIIToUTF16("Bookie markie title"),
-                                           gurl);
+  const BookmarkNode* node = CreateTestBookmark();
   BookmarkBubbleController* controller = ControllerForNode(node);
   EXPECT_TRUE(controller);
-  EXPECT_TRUE(model->IsBookmarked(gurl));
+
+  BookmarkModel* model = GetBookmarkModel();
+  EXPECT_TRUE(model->IsBookmarked(GURL(kTestBookmarkURL)));
 
   [controller remove:controller];
-  EXPECT_FALSE(model->IsBookmarked(gurl));
+  EXPECT_FALSE(model->IsBookmarked(GURL(kTestBookmarkURL)));
   EXPECT_TRUE(IsWindowClosing());
 }
 
 // Confirm picking "choose another folder" caused edit: to be called.
 TEST_F(BookmarkBubbleControllerTest, PopUpSelectionChanged) {
   BookmarkModel* model = GetBookmarkModel();
-  GURL gurl("http://www.google.com");
   const BookmarkNode* node = model->AddURL(model->bookmark_bar_node(),
                                            0, ASCIIToUTF16("super-title"),
-                                           gurl);
+                                           GURL(kTestBookmarkURL));
   BookmarkBubbleController* controller = ControllerForNode(node);
   EXPECT_TRUE(controller);
 
@@ -390,38 +393,29 @@
 // them pressing escape. The bookmark should not be there.
 TEST_F(BookmarkBubbleControllerTest, EscapeRemovesNewBookmark) {
   BookmarkModel* model = GetBookmarkModel();
-  GURL gurl("http://www.google.com");
-  const BookmarkNode* node = model->AddURL(model->bookmark_bar_node(),
-                                           0,
-                                           ASCIIToUTF16("Bookie markie title"),
-                                           gurl);
+  const BookmarkNode* node = CreateTestBookmark();
   BookmarkBubbleController* controller =
       [[BookmarkBubbleController alloc]
-          initWithParentWindow:test_window()
-                         model:BookmarkModelFactory::GetForProfile(profile())
+          initWithParentWindow:browser()->window()->GetNativeWindow()
+                         model:model
                           node:node
              alreadyBookmarked:NO];  // The last param is the key difference.
   EXPECT_TRUE([controller window]);
   // Calls release on controller.
   [controller cancel:nil];
-  EXPECT_FALSE(model->IsBookmarked(gurl));
+  EXPECT_FALSE(model->IsBookmarked(GURL(kTestBookmarkURL)));
 }
 
 // Create a controller where the bookmark already existed prior to clicking
 // the star and test that sending a cancel command doesn't change the state
 // of the bookmark.
 TEST_F(BookmarkBubbleControllerTest, EscapeDoesntTouchExistingBookmark) {
-  BookmarkModel* model = GetBookmarkModel();
-  GURL gurl("http://www.google.com");
-  const BookmarkNode* node = model->AddURL(model->bookmark_bar_node(),
-                                           0,
-                                           ASCIIToUTF16("Bookie markie title"),
-                                           gurl);
+  const BookmarkNode* node = CreateTestBookmark();
   BookmarkBubbleController* controller = ControllerForNode(node);
   EXPECT_TRUE(controller);
 
   [(id)controller cancel:nil];
-  EXPECT_TRUE(model->IsBookmarked(gurl));
+  EXPECT_TRUE(GetBookmarkModel()->IsBookmarked(GURL(kTestBookmarkURL)));
 }
 
 // Confirm indentation of items in pop-up menu
@@ -458,6 +452,25 @@
   }
 }
 
+// Confirm that the sync promo is displayed when the user is not signed in.
+TEST_F(BookmarkBubbleControllerTest, SyncPromoNotSignedIn) {
+  const BookmarkNode* node = CreateTestBookmark();
+  BookmarkBubbleController* controller = ControllerForNode(node);
+
+  EXPECT_EQ(1u, [[controller.syncPromoPlaceholder subviews] count]);
+}
+
+// Confirm that the sync promo is not displayed when the user is signed in.
+TEST_F(BookmarkBubbleControllerTest, SyncPromoSignedIn) {
+  SigninManager* signin = SigninManagerFactory::GetForProfile(profile());
+  signin->SetAuthenticatedUsername("fake_username");
+
+  const BookmarkNode* node = CreateTestBookmark();
+  BookmarkBubbleController* controller = ControllerForNode(node);
+
+  EXPECT_EQ(0u, [[controller.syncPromoPlaceholder subviews] count]);
+}
+
 }  // namespace
 
 @implementation NSApplication (BookmarkBubbleUnitTest)
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_sync_promo_controller.h b/chrome/browser/ui/cocoa/bookmarks/bookmark_sync_promo_controller.h
new file mode 100644
index 0000000..fb4fe60
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_sync_promo_controller.h
@@ -0,0 +1,37 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_COCOA_BOOKMARKS_BOOKMARK_SYNC_PROMO_CONTROLLER_H_
+#define CHROME_BROWSER_UI_COCOA_BOOKMARKS_BOOKMARK_SYNC_PROMO_CONTROLLER_H_
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/mac/scoped_nsobject.h"
+
+class Browser;
+@class HyperlinkTextView;
+
+// Controller of the bookmark sync promo displayed at the bottom of the
+// bookmark bubble.
+@interface BookmarkSyncPromoController : NSViewController<NSTextViewDelegate> {
+ @private
+  // The browser in which the sign in page will be loaded.
+  Browser* browser_;  // weak
+
+  // The text view that displays the promo message. Ownership is shared between
+  // the controller and its view.
+  base::scoped_nsobject<HyperlinkTextView> textView_;
+}
+
+@property(nonatomic, readonly) CGFloat borderWidth;
+
+- (id)initWithBrowser:(Browser*)browser;
+
+// Preferred height of the sync promo view for a given width. The border is
+// is included in the provided width and in the returned height.
+- (CGFloat)preferredHeightForWidth:(CGFloat)width;
+
+@end
+
+#endif  // CHROME_BROWSER_UI_COCOA_BOOKMARKS_BOOKMARK_SYNC_PROMO_CONTROLLER_H_
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_sync_promo_controller.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_sync_promo_controller.mm
new file mode 100644
index 0000000..ce2ee47
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_sync_promo_controller.mm
@@ -0,0 +1,115 @@
+// Copyright 2013 The Chromium 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/bookmarks/bookmark_sync_promo_controller.h"
+
+#include "base/strings/sys_string_conversions.h"
+#include "chrome/browser/ui/chrome_pages.h"
+#include "chrome/browser/ui/chrome_style.h"
+#import "chrome/browser/ui/cocoa/hyperlink_text_view.h"
+#include "chrome/browser/ui/sync/sync_promo_ui.h"
+#include "grit/generated_resources.h"
+#include "skia/ext/skia_utils_mac.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/l10n/l10n_util_mac.h"
+
+namespace {
+
+// Remove underlining from the specified range of characters in a text view.
+void RemoveUnderlining(NSTextView* textView, int offset, int length) {
+  [textView setLinkTextAttributes:nil];
+  NSTextStorage* text = [textView textStorage];
+  NSRange range = NSMakeRange(offset, length);
+  [text addAttribute:NSUnderlineStyleAttributeName
+               value:[NSNumber numberWithInt:NSUnderlineStyleNone]
+               range:range];
+}
+
+const SkColor kTextColor = SkColorSetRGB(0x66, 0x66, 0x66);
+const SkColor kBackgroundColor = SkColorSetRGB(0xf5, 0xf5, 0xf5);
+const SkColor kBorderColor = SkColorSetRGB(0xe5, 0xe5, 0xe5);
+
+// Vertical padding of the promo (dp).
+const CGFloat kVerticalPadding = 15;
+
+// Width of the border (dp).
+const CGFloat kBorderWidth = 1.0;
+
+// Font size of the promo text (pt).
+const int kFontSize = 11;
+
+}  // namespace
+
+@implementation BookmarkSyncPromoController
+
+- (id)initWithBrowser:(Browser*)browser {
+  if ((self = [super init])) {
+    browser_ = browser;
+  }
+  return self;
+}
+
+- (CGFloat)borderWidth {
+  return kBorderWidth;
+}
+
+- (CGFloat)preferredHeightForWidth:(CGFloat)width {
+  CGFloat availableWidth =
+      width - (2 * chrome_style::kHorizontalPadding) - (2 * kBorderWidth);
+  NSRect frame = [[textView_ textStorage]
+      boundingRectWithSize:NSMakeSize(availableWidth, 0.0)
+                   options:NSStringDrawingUsesLineFragmentOrigin];
+  return frame.size.height + (2 * kVerticalPadding) + (2 * kBorderWidth);
+}
+
+- (void)loadView {
+  NSBox* promoView = [[[NSBox alloc] init] autorelease];
+  [promoView setBoxType:NSBoxCustom];
+  [promoView setFillColor:gfx::SkColorToDeviceNSColor(kBackgroundColor)];
+  [promoView setContentViewMargins:NSMakeSize(chrome_style::kHorizontalPadding,
+                                              kVerticalPadding)];
+  [promoView setBorderType:NSLineBorder];
+  [promoView setBorderWidth:kBorderWidth];
+  [promoView setBorderColor:gfx::SkColorToDeviceNSColor(kBorderColor)];
+
+  // Add the sync promo text.
+  size_t offset;
+  const string16 linkText = l10n_util::GetStringUTF16(
+      IDS_BOOKMARK_SYNC_PROMO_LINK);
+  const string16 promoText =  l10n_util::GetStringFUTF16(
+      IDS_BOOKMARK_SYNC_PROMO_MESSAGE,
+      linkText, &offset);
+  const string16 promoTextWithoutLink =
+      promoText.substr(0, offset) +
+      promoText.substr(offset + linkText.size());
+
+  NSFont* font = [NSFont labelFontOfSize:kFontSize];
+  NSColor* linkColor = gfx::SkColorToCalibratedNSColor(
+      chrome_style::GetLinkColor());
+
+  textView_.reset([[HyperlinkTextView alloc] init]);
+  [textView_ setMessageAndLink:base::SysUTF16ToNSString(promoTextWithoutLink)
+                      withLink:base::SysUTF16ToNSString(linkText)
+                      atOffset:offset
+                          font:font
+                  messageColor:gfx::SkColorToDeviceNSColor(kTextColor)
+                     linkColor:linkColor];
+  [[textView_ textContainer] setLineFragmentPadding:0.0];
+  RemoveUnderlining(textView_, offset, linkText.size());
+  [textView_ setDelegate:self];
+
+  [promoView setContentView:textView_];
+
+  [self setView:promoView];
+}
+
+- (BOOL)textView:(NSTextView *)textView
+   clickedOnLink:(id)link
+         atIndex:(NSUInteger)charIndex {
+  chrome::ShowBrowserSignin(browser_, SyncPromoUI::SOURCE_BOOKMARK_BUBBLE);
+  return YES;
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_sync_promo_controller_unittest.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_sync_promo_controller_unittest.mm
new file mode 100644
index 0000000..3af5003
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_sync_promo_controller_unittest.mm
@@ -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.
+
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_sync_promo_controller.h"
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/basictypes.h"
+#include "base/mac/scoped_nsobject.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/test/base/browser_with_test_window_test.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+typedef BrowserWithTestWindowTest BookmarkSyncPromoControllerTest;
+
+TEST_F(BookmarkSyncPromoControllerTest, SignInLink) {
+  int starting_tab_count = browser()->tab_strip_model()->count();
+
+  base::scoped_nsobject<BookmarkSyncPromoController> syncPromo(
+      [[BookmarkSyncPromoController alloc] initWithBrowser:browser()]);
+
+  // Simulate clicking the "Sign in" link.
+  [syncPromo textView:nil clickedOnLink:nil atIndex:0u];
+
+  // A new tab should have been opened.
+  int tab_count = browser()->tab_strip_model()->count();
+  EXPECT_EQ(starting_tab_count + 1, tab_count);
+}
+
+}  // namespace
\ No newline at end of file
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 05304e8..b80a2a8 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
@@ -5,6 +5,7 @@
 #import "chrome/browser/ui/cocoa/browser/avatar_menu_bubble_controller.h"
 
 #include "base/mac/scoped_nsobject.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/message_loop/message_pump_mac.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/prefs/pref_service_syncable.h"
@@ -142,7 +143,7 @@
 @interface TestingAvatarMenuItemController : AvatarMenuItemController
                                                  <NSAnimationDelegate> {
  @private
-  scoped_refptr<base::MessagePumpNSRunLoop> pump_;
+  scoped_ptr<base::MessagePumpNSRunLoop> pump_;
 }
 // After calling |-highlightForEventType:| an animation will possibly be
 // started. Since the animation is non-blocking, the run loop will need to be
@@ -152,8 +153,8 @@
 
 @implementation TestingAvatarMenuItemController
 - (void)runMessagePump {
-  if (!pump_.get())
-    pump_ = new base::MessagePumpNSRunLoop;
+  if (!pump_)
+    pump_.reset(new base::MessagePumpNSRunLoop);
   pump_->Run(NULL);
 }
 
diff --git a/chrome/browser/ui/cocoa/browser_window_cocoa.mm b/chrome/browser/ui/cocoa/browser_window_cocoa.mm
index 796d9ef..f18ab51 100644
--- a/chrome/browser/ui/cocoa/browser_window_cocoa.mm
+++ b/chrome/browser/ui/cocoa/browser_window_cocoa.mm
@@ -49,6 +49,7 @@
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/web_applications/web_app_ui.h"
 #include "chrome/browser/web_applications/web_app.h"
+#include "chrome/common/chrome_switches.h"
 #include "chrome/common/crash_keys.h"
 #include "chrome/common/pref_names.h"
 #include "content/public/browser/native_web_keyboard_event.h"
@@ -316,8 +317,8 @@
           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());
+      browser_->tab_strip_model()->GetActiveWebContents()->
+          GetLastCommittedURL().possibly_invalid_spec());
 
   [controller_ zoomChangedForActiveTab:can_show_bubble ? YES : NO];
 }
@@ -370,6 +371,16 @@
 
 void BrowserWindowCocoa::EnterFullscreen(
       const GURL& url, FullscreenExitBubbleType bubble_type) {
+  // When simplified fullscreen is enabled, always enter normal fullscreen.
+  const CommandLine* command_line = CommandLine::ForCurrentProcess();
+  if (command_line->HasSwitch(switches::kEnableSimplifiedFullscreen)) {
+    if (url.is_empty())
+      [controller_ enterFullscreen];
+    else
+      [controller_ enterFullscreenForURL:url bubbleType:bubble_type];
+    return;
+  }
+
   [controller_ enterPresentationModeForURL:url
                                 bubbleType:bubble_type];
 }
@@ -621,6 +632,10 @@
 }
 
 void BrowserWindowCocoa::EnterFullscreenWithChrome() {
+  // This method cannot be called if simplified fullscreen is enabled.
+  const CommandLine* command_line = CommandLine::ForCurrentProcess();
+  DCHECK(!command_line->HasSwitch(switches::kEnableSimplifiedFullscreen));
+
   CHECK(chrome::mac::SupportsSystemFullscreen());
   if ([controller_ inPresentationMode])
     [controller_ exitPresentationMode];
@@ -629,10 +644,20 @@
 }
 
 bool BrowserWindowCocoa::IsFullscreenWithChrome() {
+  // The WithChrome mode does not exist when simplified fullscreen is enabled.
+  const CommandLine* command_line = CommandLine::ForCurrentProcess();
+  if (command_line->HasSwitch(switches::kEnableSimplifiedFullscreen))
+    return false;
   return IsFullscreen() && ![controller_ inPresentationMode];
 }
 
 bool BrowserWindowCocoa::IsFullscreenWithoutChrome() {
+  // Presentation mode does not exist if simplified fullscreen is enabled.  The
+  // WithoutChrome mode simply maps to whether or not the window is fullscreen.
+  const CommandLine* command_line = CommandLine::ForCurrentProcess();
+  if (command_line->HasSwitch(switches::kEnableSimplifiedFullscreen))
+    return IsFullscreen();
+
   return IsFullscreen() && [controller_ inPresentationMode];
 }
 
diff --git a/chrome/browser/ui/cocoa/browser_window_controller.h b/chrome/browser/ui/cocoa/browser_window_controller.h
index 89f7680..e0dbace 100644
--- a/chrome/browser/ui/cocoa/browser_window_controller.h
+++ b/chrome/browser/ui/cocoa/browser_window_controller.h
@@ -311,8 +311,9 @@
 // Gets the window style.
 - (ThemedWindowStyle)themedWindowStyle;
 
-// Gets the pattern phase for the window.
-- (NSPoint)themePatternPhase;
+// Returns the pattern phase for |alignment|. If the window does not have a tab
+// strip, the phase for THEME_PATTERN_ALIGN_WITH_FRAME is always returned.
+- (NSPoint)themePatternPhaseForAlignment:(ThemePatternAlignment)alignment;
 
 // Return the point to which a bubble window's arrow should point, in window
 // coordinates.
@@ -409,6 +410,12 @@
                          bubbleType:(FullscreenExitBubbleType)bubbleType;
 - (void)exitPresentationMode;
 
+// For simplified fullscreen: Enters fullscreen for a tab at a URL. The |url|
+// is guaranteed to be non-empty; see -enterFullscreen for the user-initiated
+// fullscreen mode. Called on Snow Leopard and Lion+.
+- (void)enterFullscreenForURL:(const GURL&)url
+                   bubbleType:(FullscreenExitBubbleType)bubbleType;
+
 // Returns presentation mode state.  This method is safe to call on all OS
 // versions.
 - (BOOL)inPresentationMode;
diff --git a/chrome/browser/ui/cocoa/browser_window_controller.mm b/chrome/browser/ui/cocoa/browser_window_controller.mm
index b9aa9e6..bef4fa9 100644
--- a/chrome/browser/ui/cocoa/browser_window_controller.mm
+++ b/chrome/browser/ui/cocoa/browser_window_controller.mm
@@ -1660,10 +1660,13 @@
   return style;
 }
 
-- (NSPoint)themePatternPhase {
+- (NSPoint)themePatternPhaseForAlignment:(ThemePatternAlignment)alignment {
   NSView* windowChromeView = [[[self window] contentView] superview];
+  NSView* tabStripView = nil;
+  if (alignment == THEME_PATTERN_ALIGN_WITH_TAB_STRIP && [self hasTabStrip])
+    tabStripView = [self tabStripView];
   return [BrowserWindowUtils themePatternPhaseFor:windowChromeView
-                                     withTabStrip:[self tabStripView]];
+                                     withTabStrip:tabStripView];
 }
 
 - (NSPoint)bookmarkBubblePoint {
@@ -2010,7 +2013,7 @@
   if (!chrome::IsCommandEnabled(browser_.get(), IDC_FULLSCREEN))
     return;
 
-  if (chrome::mac::SupportsSystemFullscreen()) {
+  if (chrome::mac::SupportsSystemFullscreen() && !fullscreenWindow_) {
     enteredPresentationModeFromFullscreen_ = YES;
     if ([[self window] isKindOfClass:[FramedBrowserWindow class]])
       [static_cast<FramedBrowserWindow*>([self window]) toggleSystemFullScreen];
@@ -2034,6 +2037,7 @@
                            bubbleType:(FullscreenExitBubbleType)bubbleType {
   fullscreenUrl_ = url;
   fullscreenBubbleType_ = bubbleType;
+  [self layoutSubviews];
   [self showFullscreenExitBubbleIfNecessary];
 }
 
@@ -2115,6 +2119,16 @@
   [self setPresentationMode:NO url:GURL() bubbleType:FEB_TYPE_NONE];
 }
 
+- (void)enterFullscreenForURL:(const GURL&)url
+                   bubbleType:(FullscreenExitBubbleType)bubbleType {
+  // This method may only be called in simplified fullscreen mode.
+  const CommandLine* command_line = CommandLine::ForCurrentProcess();
+  DCHECK(command_line->HasSwitch(switches::kEnableSimplifiedFullscreen));
+
+  [self enterFullscreenForSnowLeopard];
+  [self updateFullscreenExitBubbleURL:url bubbleType:bubbleType];
+}
+
 - (BOOL)inPresentationMode {
   return presentationModeController_.get() &&
       [presentationModeController_ inPresentationMode];
diff --git a/chrome/browser/ui/cocoa/browser_window_controller_private.mm b/chrome/browser/ui/cocoa/browser_window_controller_private.mm
index 9ff7da1..382e28a 100644
--- a/chrome/browser/ui/cocoa/browser_window_controller_private.mm
+++ b/chrome/browser/ui/cocoa/browser_window_controller_private.mm
@@ -234,7 +234,7 @@
 
   // 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.
-  if (inPresentationMode)
+  if (inPresentationMode || !fullscreenUrl_.is_empty())
     maxY = NSMaxY(contentBounds);
 
   // Also place the info bar container immediate below the toolbar, except in
@@ -613,11 +613,9 @@
   [self layoutSubviews];
 }
 
+// TODO(rohitrao): This method is misnamed now, since there is a flag that
+// enables 10.6-style fullscreen on newer OSes.
 - (void)enterFullscreenForSnowLeopard {
-  // TODO(rohitrao): This method is misnamed now, since there is a flag that
-  // enables 10.6-style fullscreen on newer OSes.
-  DCHECK(!chrome::mac::SupportsSystemFullscreen());
-
   // Fade to black.
   const CGDisplayReservationInterval kFadeDurationSeconds = 0.6;
   Boolean didFadeOut = NO;
@@ -638,8 +636,16 @@
   [self moveViewsForFullscreenForSnowLeopard:YES
                                regularWindow:[self window]
                             fullscreenWindow:fullscreenWindow_.get()];
-  [self adjustUIForPresentationMode:YES];
-  [self setPresentationModeInternal:YES forceDropdown:NO];
+
+  // When simplified fullscreen is enabled, do not enter presentation mode.
+  const CommandLine* command_line = CommandLine::ForCurrentProcess();
+  if (command_line->HasSwitch(switches::kEnableSimplifiedFullscreen)) {
+    // TODO(rohitrao): Add code to manage the menubar here.
+  } else {
+    [self adjustUIForPresentationMode:YES];
+    [self setPresentationModeInternal:YES forceDropdown:NO];
+  }
+
   [self layoutSubviews];
 
   [self windowDidEnterFullScreen:nil];
@@ -668,6 +674,13 @@
         kCGDisplayBlendSolidColor, 0.0, 0.0, 0.0, /*synchronous=*/true);
   }
 
+  // When simplified fullscreen is enabled, the menubar status is managed
+  // directly by BWC.
+  const CommandLine* command_line = CommandLine::ForCurrentProcess();
+  if (command_line->HasSwitch(switches::kEnableSimplifiedFullscreen)) {
+    // TODO(rohitrao): Add code to manage the menubar here.
+  }
+
   [self windowWillExitFullScreen:nil];
 
   [self moveViewsForFullscreenForSnowLeopard:NO
diff --git a/chrome/browser/ui/cocoa/chrome_browser_window.mm b/chrome/browser/ui/cocoa/chrome_browser_window.mm
index 24e2623..9855072 100644
--- a/chrome/browser/ui/cocoa/chrome_browser_window.mm
+++ b/chrome/browser/ui/cocoa/chrome_browser_window.mm
@@ -24,11 +24,11 @@
   return [delegate themedWindowStyle];
 }
 
-- (NSPoint)themePatternPhase {
+- (NSPoint)themePatternPhaseForAlignment:(ThemePatternAlignment)alignment {
   id delegate = [self delegate];
-  if (![delegate respondsToSelector:@selector(themePatternPhase)])
+  if (![delegate respondsToSelector:@selector(themePatternPhaseForAlignment:)])
     return NSZeroPoint;
-  return [delegate themePatternPhase];
+  return [delegate themePatternPhaseForAlignment:alignment];
 }
 
 @end
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 5ec022f..1fd2d9e 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
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "base/mac/scoped_nsobject.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/message_loop/message_pump_mac.h"
 #import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_animation.h"
@@ -12,7 +13,7 @@
                                                    <NSAnimationDelegate> {
  @private
   CGFloat frameCount_;
-  scoped_refptr<base::MessagePumpNSRunLoop> message_pump_;
+  scoped_ptr<base::MessagePumpNSRunLoop> message_pump_;
 }
 
 - (void)runAnimation:(NSAnimation*)animation;
@@ -23,7 +24,7 @@
 
 - (id)init {
   if ((self = [super init]))
-    message_pump_ = new base::MessagePumpNSRunLoop;
+    message_pump_.reset(new base::MessagePumpNSRunLoop);
   return self;
 }
 
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 73202e8..6651e69 100644
--- a/chrome/browser/ui/cocoa/constrained_window/constrained_window_mac.h
+++ b/chrome/browser/ui/cocoa/constrained_window/constrained_window_mac.h
@@ -41,6 +41,8 @@
   void PulseWebContentsModalDialog();
   web_modal::NativeWebContentsModalDialog GetNativeDialog();
 
+  void SetPreventCloseOnLoadStart(bool prevent);
+
  private:
   // Gets the parent window of the dialog.
   NSWindow* GetParentWindow() const;
@@ -54,6 +56,9 @@
 
   // This is true if the constrained window has been shown.
   bool shown_;
+
+  // This is true while the constrained window is closing.
+  bool closing_;
 };
 
 #endif  // CHROME_BROWSER_UI_COCOA_CONSTRAINED_WINDOW_CONSTRAINED_WINDOW_MAC_
diff --git a/chrome/browser/ui/cocoa/constrained_window/constrained_window_mac.mm b/chrome/browser/ui/cocoa/constrained_window/constrained_window_mac.mm
index df302df..a7cb5be 100644
--- a/chrome/browser/ui/cocoa/constrained_window/constrained_window_mac.mm
+++ b/chrome/browser/ui/cocoa/constrained_window/constrained_window_mac.mm
@@ -25,7 +25,8 @@
     : delegate_(delegate),
       web_contents_(web_contents),
       sheet_([sheet retain]),
-      shown_(false) {
+      shown_(false),
+      closing_(false) {
   DCHECK(web_contents);
   DCHECK(sheet_.get());
   WebContentsModalDialogManager* web_contents_modal_dialog_manager =
@@ -54,6 +55,10 @@
 }
 
 void ConstrainedWindowMac::CloseWebContentsModalDialog() {
+  if (closing_)
+    return;
+
+  closing_ = true;
   [[ConstrainedWindowSheetController controllerForSheet:sheet_]
       closeSheet:sheet_];
   WebContentsModalDialogManager* web_contents_modal_dialog_manager =
@@ -78,6 +83,14 @@
   return this;
 }
 
+void ConstrainedWindowMac::SetPreventCloseOnLoadStart(bool prevent) {
+  WebContentsModalDialogManager* web_contents_modal_dialog_manager =
+      WebContentsModalDialogManager::FromWebContents(web_contents_);
+  web_contents_modal_dialog_manager->SetPreventCloseOnLoadStart(
+      GetNativeDialog(),
+      prevent);
+}
+
 NSWindow* ConstrainedWindowMac::GetParentWindow() const {
   // Tab contents in a tabbed browser may not be inside a window. For this
   // reason use a browser window if possible.
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 ce723c9..a7761b1 100644
--- a/chrome/browser/ui/cocoa/content_settings/cookie_details_unittest.mm
+++ b/chrome/browser/ui/cocoa/content_settings/cookie_details_unittest.mm
@@ -142,7 +142,8 @@
   content::IndexedDBInfo info(origin,
                               size,
                               last_modified,
-                              file_path);
+                              file_path,
+                              0);
 
   details.reset([[CocoaCookieDetails alloc] initWithIndexedDBInfo:&info]);
 
diff --git a/chrome/browser/ui/cocoa/drag_util.mm b/chrome/browser/ui/cocoa/drag_util.mm
index b991fec..2f5d596 100644
--- a/chrome/browser/ui/cocoa/drag_util.mm
+++ b/chrome/browser/ui/cocoa/drag_util.mm
@@ -8,13 +8,13 @@
 #include "chrome/browser/profiles/profile.h"
 #include "content/public/browser/plugin_service.h"
 #include "content/public/common/url_constants.h"
+#include "content/public/common/webplugininfo.h"
 #include "ipc/ipc_message.h"
 #include "net/base/mime_util.h"
 #include "net/base/net_util.h"
 #import "third_party/mozilla/NSPasteboard+Utils.h"
 #import "ui/base/dragdrop/cocoa_dnd_util.h"
 #include "url/gurl.h"
-#include "webkit/plugins/webplugininfo.h"
 
 using content::PluginService;
 
@@ -39,7 +39,7 @@
   // TODO(bauerb): This possibly uses stale information, but it's guaranteed not
   // to do disk access.
   bool allow_wildcard = false;
-  webkit::WebPluginInfo plugin;
+  content::WebPluginInfo plugin;
   return PluginService::GetInstance()->GetPluginInfo(
       -1,                // process ID
       MSG_ROUTING_NONE,  // routing ID
diff --git a/chrome/browser/ui/cocoa/extensions/media_galleries_dialog_cocoa_unittest.mm b/chrome/browser/ui/cocoa/extensions/media_galleries_dialog_cocoa_unittest.mm
index 7217e04..1eb8fb2 100644
--- a/chrome/browser/ui/cocoa/extensions/media_galleries_dialog_cocoa_unittest.mm
+++ b/chrome/browser/ui/cocoa/extensions/media_galleries_dialog_cocoa_unittest.mm
@@ -6,7 +6,6 @@
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/media_galleries/media_galleries_dialog_controller_mock.h"
 #include "chrome/browser/storage_monitor/storage_info.h"
-#include "chrome/browser/storage_monitor/test_storage_monitor.h"
 #include "chrome/browser/ui/cocoa/extensions/media_galleries_dialog_cocoa.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -29,8 +28,6 @@
 }
 
 class MediaGalleriesDialogTest : public testing::Test {
- private:
-  test::TestStorageMonitor test_storage_monitor_;
 };
 
 // Tests that checkboxes are initialized according to the contents of
diff --git a/chrome/browser/ui/cocoa/find_bar/find_bar_view.mm b/chrome/browser/ui/cocoa/find_bar/find_bar_view.mm
index eb7e9d5..2668046 100644
--- a/chrome/browser/ui/cocoa/find_bar/find_bar_view.mm
+++ b/chrome/browser/ui/cocoa/find_bar/find_bar_view.mm
@@ -70,7 +70,8 @@
     [path addClip];
 
     // Set the pattern phase
-    NSPoint phase = [[self window] themePatternPhase];
+    NSPoint phase = [[self window]
+        themePatternPhaseForAlignment:THEME_PATTERN_ALIGN_WITH_TAB_STRIP];
 
     [context cr_setPatternPhase:phase forView:self];
     [super drawBackgroundWithOpaque:YES];
diff --git a/chrome/browser/ui/cocoa/history_overlay_controller_unittest.mm b/chrome/browser/ui/cocoa/history_overlay_controller_unittest.mm
index 96ab915..f92ccb9 100644
--- a/chrome/browser/ui/cocoa/history_overlay_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/history_overlay_controller_unittest.mm
@@ -6,7 +6,7 @@
 
 #import <QuartzCore/QuartzCore.h>
 
-#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/message_loop/message_pump_mac.h"
 #import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "third_party/ocmock/gtest_support.h"
@@ -53,7 +53,7 @@
       [[HistoryOverlayController alloc] initForMode:kHistoryOverlayModeBack]);
   [controller showPanelForView:test_view()];
 
-  scoped_refptr<base::MessagePumpNSRunLoop> message_pump(
+  scoped_ptr<base::MessagePumpNSRunLoop> message_pump(
       new base::MessagePumpNSRunLoop);
 
   id mock = [OCMockObject partialMockForObject:controller];
@@ -61,8 +61,9 @@
   [[[mock expect] andForwardToRealObject] dismiss];
 
   // Called after |-animationDidStop:finished:|.
+  base::MessagePumpNSRunLoop* weak_message_pump = message_pump.get();
   void (^quit_loop)(NSInvocation* invocation) = ^(NSInvocation* invocation) {
-      message_pump->Quit();
+      weak_message_pump->Quit();
   };
   // Set up the mock to first forward to the real implementation and then call
   // the above block to quit the run loop.
diff --git a/chrome/browser/ui/cocoa/infobars/translate_infobar_unittest.mm b/chrome/browser/ui/cocoa/infobars/translate_infobar_unittest.mm
index e5ae2a0..2c03aca 100644
--- a/chrome/browser/ui/cocoa/infobars/translate_infobar_unittest.mm
+++ b/chrome/browser/ui/cocoa/infobars/translate_infobar_unittest.mm
@@ -35,13 +35,13 @@
 
 class MockTranslateInfoBarDelegate : public TranslateInfoBarDelegate {
  public:
-  MockTranslateInfoBarDelegate(TranslateInfoBarDelegate::Type type,
+  MockTranslateInfoBarDelegate(InfoBarService* infobar_service,
+                               TranslateInfoBarDelegate::Type type,
                                TranslateErrors::Type error,
-                               InfoBarService* infobar_service,
                                PrefService* prefs,
                                ShortcutConfiguration config)
-      : TranslateInfoBarDelegate(type, error, infobar_service, prefs,
-                                 config, "en", "es") {
+      : TranslateInfoBarDelegate(infobar_service, type, NULL, "en", "es", error,
+                                 prefs, config) {
   }
 
   MOCK_METHOD0(Translate, void());
@@ -86,18 +86,12 @@
     config.never_translate_min_count = 3;
     config.always_translate_min_count = 3;
     infobar_delegate_.reset(new MockTranslateInfoBarDelegate(
-        type,
-        error,
-        infobar_service,
-        profile->GetPrefs(),
-        config));
+        infobar_service, type, error, profile->GetPrefs(), config));
     [[infobar_controller_ view] removeFromSuperview];
-    scoped_ptr<InfoBar> infobar(
-        static_cast<InfoBarDelegate*>(infobar_delegate_.get())->
-            CreateInfoBar(infobar_service));
-    infobar_controller_.reset(
-        reinterpret_cast<TranslateInfoBarControllerBase*>(
-            infobar->controller()));
+    scoped_ptr<InfoBar> infobar(static_cast<InfoBarDelegate*>(
+        infobar_delegate_.get())->CreateInfoBar(infobar_service));
+    infobar_controller_.reset(reinterpret_cast<TranslateInfoBarControllerBase*>(
+        infobar->controller()));
     // We need to set the window to be wide so that the options button
     // doesn't overlap the other buttons.
     [test_window() setContentSize:NSMakeSize(2000, 500)];
diff --git a/chrome/browser/ui/cocoa/keystone_infobar_delegate.mm b/chrome/browser/ui/cocoa/keystone_infobar_delegate.mm
index 4ce489c..5f04437 100644
--- a/chrome/browser/ui/cocoa/keystone_infobar_delegate.mm
+++ b/chrome/browser/ui/cocoa/keystone_infobar_delegate.mm
@@ -75,20 +75,19 @@
 // static
 void KeystonePromotionInfoBarDelegate::Create() {
   Browser* browser = chrome::GetLastActiveBrowser();
-  if (browser) {
-    content::WebContents* webContents =
-        browser->tab_strip_model()->GetActiveWebContents();
-
-    if (webContents) {
-      InfoBarService* infobar_service =
-          InfoBarService::FromWebContents(webContents);
-      infobar_service->AddInfoBar(scoped_ptr<InfoBarDelegate>(
-          new KeystonePromotionInfoBarDelegate(
-              infobar_service,
-              Profile::FromBrowserContext(
-                  webContents->GetBrowserContext())->GetPrefs())));
-    }
-  }
+  if (!browser)
+    return;
+  content::WebContents* webContents =
+      browser->tab_strip_model()->GetActiveWebContents();
+  if (!webContents)
+    return;
+  InfoBarService* infobar_service =
+      InfoBarService::FromWebContents(webContents);
+  infobar_service->AddInfoBar(scoped_ptr<InfoBarDelegate>(
+      new KeystonePromotionInfoBarDelegate(
+          infobar_service,
+          Profile::FromBrowserContext(
+              webContents->GetBrowserContext())->GetPrefs())));
 }
 
 KeystonePromotionInfoBarDelegate::KeystonePromotionInfoBarDelegate(
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
deleted file mode 100644
index f0a38ac..0000000
--- a/chrome/browser/ui/cocoa/location_bar/action_box_menu_bubble_controller.h
+++ /dev/null
@@ -1,107 +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_COCOA_LOCATION_BAR_ACTION_BOX_MENU_BUBBLE_CONTROLLER_H_
-#define CHROME_BROWSER_UI_COCOA_LOCATION_BAR_ACTION_BOX_MENU_BUBBLE_CONTROLLER_H_
-
-#import <Cocoa/Cocoa.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"
-
-class ActionBoxMenuModel;
-class ExtensionIconLoaderBridge;
-class Profile;
-
-// This window controller manages the action box popup menu.
-@interface ActionBoxMenuBubbleController : BaseBubbleController {
- @private
-  Profile* profile_;
-
-  // The model that contains the data from the backend.
-  scoped_ptr<ActionBoxMenuModel> model_;
-
-  // Array of the below view controllers.
-  base::scoped_nsobject<NSMutableArray> items_;
-}
-
-// Designated initializer. |point| must be in screen coordinates.
-- (id)initWithModel:(scoped_ptr<ActionBoxMenuModel>)model
-       parentWindow:(NSWindow*)parent
-         anchoredAt:(NSPoint)point
-            profile:(Profile*)profile;
-
-// Accesses the model.
-- (ActionBoxMenuModel*)model;
-
-- (NSMutableArray*)items;
-
-// Executes the action of a given menu item.
-- (IBAction)itemSelected:(id)sender;
-
-@end
-
-////////////////////////////////////////////////////////////////////////////////
-
-// This view controller manages the menu item XIB.
-@interface ActionBoxMenuItemController : NSViewController {
- @private
-  // The parent menu controller owns this.
-  __weak ActionBoxMenuBubbleController* controller_;
-
-  size_t modelIndex_;
-
-  // Tracks whether this item is currently highlighted.
-  BOOL isHighlighted_;
-
-  // If the icon comes from an extension, this wraps the extension icon loader.
-  scoped_ptr<ExtensionIconLoaderBridge> extensionIconLoaderBridge_;
-
-  // Instance variables that back the outlets.
-  IBOutlet __weak NSImageView* iconView_;
-  IBOutlet __weak NSTextField* nameField_;
-}
-@property(readonly, nonatomic) size_t modelIndex;
-@property(assign, nonatomic) BOOL isHighlighted;
-@property(readonly, nonatomic) NSImageView* iconView;
-@property(assign, nonatomic) NSTextField* nameField;
-
-// Designated initializer.
-- (id)initWithModelIndex:(size_t)modelIndex
-          menuController:(ActionBoxMenuBubbleController*)controller
-                 profile:(Profile*)profile;
-
-// Highlights the subviews appropriately for a given event.
-- (void)highlightForEvent:(NSEvent*)event;
-
-// Execute the action of a given menu item.
-- (IBAction)itemSelected:(id)sender;
-
-// Called when |extensionIconLoaderBridge_| changes, updates |iconView_|.
-- (void)onExtensionIconImageChanged:(NSImage*)image;
-
-@end
-
-////////////////////////////////////////////////////////////////////////////////
-
-// Simple button cell to get tracking and mouse events forwarded back to the
-// view controller for changing highlight style of the item subviews. This is
-// an invisible button that underlays most of the menu item and is responsible
-// for performing the attached action.
-@interface ActionBoxMenuItemView : NSView {
- @private
-  // The controller that manages this.
-  IBOutlet __weak ActionBoxMenuItemController* viewController_;
-
-  // Used to highlight the background on hover.
-  ui::ScopedCrTrackingArea trackingArea_;
-}
-
-@property(assign, nonatomic) ActionBoxMenuItemController* viewController;
-
-@end
-
-#endif  // CHROME_BROWSER_UI_COCOA_LOCATION_BAR_ACTION_BOX_MENU_BUBBLE_CONTROLLER_H_
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
deleted file mode 100644
index d65dc50..0000000
--- a/chrome/browser/ui/cocoa/location_bar/action_box_menu_bubble_controller.mm
+++ /dev/null
@@ -1,473 +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.
-
-#import "chrome/browser/ui/cocoa/location_bar/action_box_menu_bubble_controller.h"
-
-#include "base/mac/bundle_locations.h"
-#include "base/mac/foundation_util.h"
-#include "base/mac/mac_util.h"
-#include "base/strings/sys_string_conversions.h"
-#include "chrome/browser/extensions/extension_icon_image.h"
-#import "chrome/browser/ui/cocoa/browser_window_utils.h"
-#import "chrome/browser/ui/cocoa/info_bubble_view.h"
-#import "chrome/browser/ui/cocoa/info_bubble_window.h"
-#include "chrome/browser/ui/toolbar/action_box_menu_model.h"
-#include "chrome/common/extensions/api/extension_action/action_info.h"
-#include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/extension_constants.h"
-#include "chrome/common/extensions/manifest_handlers/icons_handler.h"
-#include "grit/generated_resources.h"
-#include "grit/theme_resources.h"
-#include "skia/ext/skia_utils_mac.h"
-#import "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h"
-#import "ui/base/cocoa/cocoa_event_utils.h"
-#include "ui/base/resource/resource_bundle.h"
-#include "ui/gfx/image/image.h"
-#include "ui/gfx/image/image_skia_util_mac.h"
-#include "ui/native_theme/native_theme.h"
-
-@interface ActionBoxMenuBubbleController (Private)
-- (id)highlightedItem;
-- (void)keyDown:(NSEvent*)theEvent;
-- (void)moveDown:(id)sender;
-- (void)moveUp:(id)sender;
-- (void)highlightNextItemByDelta:(NSInteger)delta;
-- (void)highlightItem:(ActionBoxMenuItemController*)newItem;
-@end
-
-@interface ActionBoxMenuItemView (Private)
-- (NSColor*)highlightedMenuItemBackgroundColor;
-@end
-
-namespace {
-
-// Some reasonable values for the menu geometry.
-const CGFloat kBubbleMinWidth = 175;
-const CGFloat kBubbleMaxWidth = 800;
-
-// Distance between the top/bottom of the bubble and the first/last menu item.
-const CGFloat kVerticalPadding = 7.0;
-
-// Minimum distance between the right of a menu item and the right border.
-const CGFloat kRightMargin = 20.0;
-
-// Alpha of the black rectangle overlayed on the item hovered over.
-const CGFloat kSelectionAlpha = 0.06;
-
-}  // namespace
-
-// extension Icon Loader Bridge ////////////////////////////////////////////////
-
-class ExtensionIconLoaderBridge : public extensions::IconImage::Observer {
- public:
-  ExtensionIconLoaderBridge(Profile* profile,
-                            const extensions::Extension* extension,
-                            ActionBoxMenuItemController* controller)
-      : controller_(controller) {
-    const extensions::ActionInfo* page_launcher_info =
-        extensions::ActionInfo::GetPageLauncherInfo(extension);
-    DCHECK(page_launcher_info);
-    icon_loader_.reset(new extensions::IconImage(
-        profile,
-        extension,
-        page_launcher_info->default_icon,
-        extension_misc::EXTENSION_ICON_ACTION,
-        extensions::IconsInfo::GetDefaultAppIcon(),
-        this));
-    OnExtensionIconImageChanged(icon_loader_.get());
-  }
-
- private:
-  virtual void OnExtensionIconImageChanged(
-      extensions::IconImage* image) OVERRIDE {
-    [controller_ onExtensionIconImageChanged:
-        gfx::NSImageFromImageSkia(image->image_skia())];
-  }
-
-  scoped_ptr<extensions::IconImage> icon_loader_;
-  ActionBoxMenuItemController* controller_;  // Weak.
-
-  DISALLOW_COPY_AND_ASSIGN(ExtensionIconLoaderBridge);
-};
-
-@implementation ActionBoxMenuBubbleController
-
-- (id)initWithModel:(scoped_ptr<ActionBoxMenuModel>)model
-       parentWindow:(NSWindow*)parent
-         anchoredAt:(NSPoint)point
-            profile:(Profile*)profile {
-  // 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.
-  base::scoped_nsobject<InfoBubbleWindow> window(
-      [[InfoBubbleWindow alloc] initWithContentRect:contentRect
-                                          styleMask:NSBorderlessWindowMask
-                                            backing:NSBackingStoreBuffered
-                                              defer:NO]);
-  [window setAllowedAnimations:info_bubble::kAnimateNone];
-  if (self = [super initWithWindow:window
-                      parentWindow:parent
-                        anchoredAt:point]) {
-    profile_ = profile;
-    model_.reset(model.release());
-
-    [[self bubble] setAlignment:info_bubble::kAlignRightEdgeToAnchorEdge];
-    [[self bubble] setArrowLocation:info_bubble::kNoArrow];
-    ui::NativeTheme* nativeTheme = ui::NativeTheme::instance();
-    [[self bubble] setBackgroundColor:
-        gfx::SkColorToCalibratedNSColor(nativeTheme->GetSystemColor(
-            ui::NativeTheme::kColorId_DialogBackground))];
-    [self performLayout];
-  }
-  return self;
-}
-
-- (ActionBoxMenuModel*)model {
-  return model_.get();
-}
-
-- (NSMutableArray*)items {
-  return items_;
-}
-
-- (IBAction)itemSelected:(id)sender {
-  // If Enter is pressed but nothing is highlighted, don't activate anything.
-  if (!sender)
-    return;
-
-  // Close the current window and activate the parent browser window, otherwise
-  // the bookmark popup refuses to show.
-  [self close];
-  [BrowserWindowUtils
-      activateWindowForController:[[self parentWindow] windowController]];
-  size_t modelIndex = [sender modelIndex];
-  DCHECK(model_.get());
-  int eventFlags = ui::EventFlagsFromNSEvent([NSApp currentEvent]);
-  model_->ActivatedAt(modelIndex, eventFlags);
-}
-
-// Private /////////////////////////////////////////////////////////////////////
-
-- (void)performLayout {
-  NSView* contentView = [[self window] contentView];
-
-  // Reset the array of controllers and remove all the views.
-  items_.reset([[NSMutableArray alloc] init]);
-  [contentView setSubviews:[NSArray array]];
-
-  // Leave some space at the bottom of the menu.
-  CGFloat yOffset = kVerticalPadding;
-
-  // Keep track of a potential separator to resize it when we know the width.
-  base::scoped_nsobject<NSBox> separatorView;
-
-  // Loop over the items in reverse, constructing the menu items.
-  CGFloat width = kBubbleMinWidth;
-  CGFloat minX = NSMinX([contentView bounds]);
-  for (int i = model_->GetItemCount() - 1; i >= 0; --i) {
-    if (model_->GetTypeAt(i) == ui::MenuModel::TYPE_SEPARATOR) {
-      const CGFloat kSeparatorHeight = 1.0;
-      // Only supports one separator.
-      DCHECK(!separatorView);
-      yOffset += kVerticalPadding + kSeparatorHeight;
-      separatorView.reset([[NSBox alloc]
-          initWithFrame:NSMakeRect(0, yOffset, width, kSeparatorHeight)]);
-      [separatorView setBoxType:NSBoxCustom];
-      ui::NativeTheme* nativeTheme = ui::NativeTheme::instance();
-      [separatorView setBorderColor:
-          gfx::SkColorToCalibratedNSColor(nativeTheme->GetSystemColor(
-              ui::NativeTheme::kColorId_MenuSeparatorColor))];
-      [contentView addSubview:separatorView];
-      yOffset += kVerticalPadding;
-    } else {
-      // Create the item controller. Autorelease it because it will be owned
-      // by the |items_| array.
-      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]];
-
-      // Expand the size of the window if required to fit the menu item.
-      width = std::max(width,
-          NSMaxX([[itemController nameField] frame]) - minX + kRightMargin);
-
-      // Add the item to the content view.
-      [[itemController view] setFrameOrigin:NSMakePoint(0, yOffset)];
-      [contentView addSubview:[itemController view]];
-      yOffset += NSHeight([[itemController view] frame]);
-
-      // Keep track of the view controller.
-      [items_ addObject:itemController.get()];
-    }
-  }
-
-  // Leave some space at the top of the menu.
-  yOffset += kVerticalPadding;
-
-  // Set the window frame, clamping the width at a sensible max.
-  NSRect frame = [[self window] frame];
-  frame.size.height = yOffset;
-  frame.size.width = std::min(width, kBubbleMaxWidth);
-
-  // Resize the separator to full width.
-  if (separatorView) {
-    NSRect separatorFrame = [separatorView frame];
-    separatorFrame.size.width = width;
-    [separatorView setFrame:separatorFrame];
-  }
-
-  [[self window] setFrame:frame display:YES];
-}
-
-- (id)highlightedItem {
-  for (ActionBoxMenuItemController* item in items_.get()) {
-    if ([item isHighlighted]) {
-      return item;
-    }
-  }
-  return nil;
-}
-
-- (void)keyDown:(NSEvent*)theEvent {
-  // Interpret all possible key events. In particular, this will answer
-  // moveDown, moveUp and insertNewline so that the menu can be navigated
-  // with keystrokes.
-  [self interpretKeyEvents:[NSArray arrayWithObject:theEvent]];
-}
-
-- (void)moveDown:(id)sender {
-  [self highlightNextItemByDelta:-1];
-}
-
-- (void)moveUp:(id)sender {
-  [self highlightNextItemByDelta:1];
-}
-
-- (void)insertNewline:(id)sender {
-  [self itemSelected:[self highlightedItem]];
-}
-
-- (void)highlightNextItemByDelta:(NSInteger)delta {
-  NSUInteger count = [items_ count];
-  if (count == 0)
-    return;
-
-  // If nothing is selected, select the first (resp. last) item when going up
-  // (resp. going down). Otherwise selects the next (resp. previous) item.
-  // This code does not wrap around if something is already selected.
-
-  // First assumes nothing is selected.
-  NSUInteger newIndex = delta < 0 ? (count - 1) : 0;
-  NSUInteger oldIndex = [items_ indexOfObject:[self highlightedItem]];
-  // oldIndex will be NSNotFound when [self highlightedItem] returns nil.
-  if (oldIndex != NSNotFound) {
-    // Something is selected, move only if not already at top/bottom.
-    newIndex = oldIndex;
-    if (newIndex != (delta < 0 ? 0 : count - 1))
-      newIndex += delta;
-  }
-
-  [self highlightItem:[items_ objectAtIndex:newIndex]];
-}
-
-- (void)highlightItem:(ActionBoxMenuItemController*)newItem {
-  ActionBoxMenuItemController* oldItem = [self highlightedItem];
-  if (oldItem == newItem)
-    return;
-  [oldItem setIsHighlighted:NO];
-  [newItem setIsHighlighted:YES];
-}
-
-@end
-
-// Menu Item Controller ////////////////////////////////////////////////////////
-
-@implementation ActionBoxMenuItemController
-
-@synthesize modelIndex = modelIndex_;
-@synthesize isHighlighted = isHighlighted_;
-@synthesize iconView = iconView_;
-@synthesize nameField = nameField_;
-
-- (id)initWithModelIndex:(size_t)modelIndex
-          menuController:(ActionBoxMenuBubbleController*)controller
-                profile:(Profile*)profile {
-  if ((self = [super initWithNibName:@"ActionBoxMenuItem"
-                              bundle:base::mac::FrameworkBundle()])) {
-    modelIndex_ = modelIndex;
-    controller_ = controller;
-
-    [self loadView];
-
-    gfx::Image icon = gfx::Image();
-    ActionBoxMenuModel* model = [controller model];
-    if (model->GetIconAt(modelIndex_, &icon)) {
-      extensionIconLoaderBridge_.reset();
-      [iconView_ setImage:icon.ToNSImage()];
-    } else if (model->GetTypeAt(modelIndex_) == ui::MenuModel::TYPE_COMMAND &&
-               model->IsItemExtension(modelIndex_)) {
-      // Creating an ExtensionIconLoaderBridge will call
-      // onExtensionIconImageChanged and set the |iconView_|.
-      [iconView_ setImage:nil];
-      extensionIconLoaderBridge_.reset(new ExtensionIconLoaderBridge(
-          profile,
-          model->GetExtensionAt(modelIndex_),
-          self));
-    } else {
-      extensionIconLoaderBridge_.reset();
-      [iconView_ setImage:nil];
-    }
-
-    nameField_.stringValue = base::SysUTF16ToNSString(
-        controller.model->GetLabelAt(modelIndex_));
-  }
-  return self;
-}
-
-- (void)dealloc {
-  base::mac::ObjCCastStrict<ActionBoxMenuItemView>(
-      self.view).viewController = nil;
-  [super dealloc];
-}
-
-- (void)highlightForEvent:(NSEvent*)event {
-  switch ([event type]) {
-    case NSMouseEntered:
-      [controller_ highlightItem:self];
-      break;
-
-    case NSMouseExited:
-      [controller_ highlightItem:nil];
-      break;
-
-    default:
-      NOTREACHED();
-  };
-}
-
-- (IBAction)itemSelected:(id)sender {
-  [controller_ itemSelected:self];
-}
-
-- (void)setIsHighlighted:(BOOL)isHighlighted {
-  if (isHighlighted_ == isHighlighted)
-    return;
-
-  isHighlighted_ = isHighlighted;
-  [[self view] setNeedsDisplay:YES];
-}
-
-- (void)onExtensionIconImageChanged:(NSImage*)image {
-  [iconView_ setImage:image];
-}
-
-@end
-
-// Items from the action box menu //////////////////////////////////////////////
-
-@implementation ActionBoxMenuItemView
-
-@synthesize viewController = viewController_;
-
-- (void)updateTrackingAreas {
-  if (trackingArea_.get())
-    [self removeTrackingArea:trackingArea_.get()];
-
-  trackingArea_.reset(
-      [[CrTrackingArea alloc] initWithRect:[self bounds]
-                                   options:NSTrackingMouseEnteredAndExited |
-                                           NSTrackingActiveInKeyWindow
-                                     owner:self
-                                  userInfo:nil]);
-  [self addTrackingArea:trackingArea_.get()];
-
-  [super updateTrackingAreas];
-}
-
-- (BOOL)acceptsFirstResponder {
-  return YES;
-}
-
-- (void)mouseUp:(NSEvent*)theEvent {
-  [viewController_ itemSelected:self];
-}
-
-- (void)mouseEntered:(NSEvent*)theEvent {
-  [viewController_ highlightForEvent:theEvent];
-}
-
-- (void)mouseExited:(NSEvent*)theEvent {
-  [viewController_ highlightForEvent:theEvent];
-}
-
-- (void)drawRect:(NSRect)dirtyRect {
-  NSColor* backgroundColor = nil;
-  if ([viewController_ isHighlighted]) {
-    ui::NativeTheme* nativeTheme = ui::NativeTheme::instance();
-    backgroundColor = gfx::SkColorToCalibratedNSColor(
-        nativeTheme->GetSystemColor(
-            ui::NativeTheme::kColorId_FocusedMenuItemBackgroundColor));
-  } else {
-    backgroundColor = [NSColor clearColor];
-  }
-
-  [backgroundColor set];
-  [NSBezierPath fillRect:[self bounds]];
-}
-
-// Make sure the element is focusable for accessibility.
-- (BOOL)canBecomeKeyView {
-  return YES;
-}
-
-- (BOOL)accessibilityIsIgnored {
-  return NO;
-}
-
-- (NSArray*)accessibilityAttributeNames {
-  NSMutableArray* attributes =
-      [[[super accessibilityAttributeNames] mutableCopy] autorelease];
-  [attributes addObject:NSAccessibilityTitleAttribute];
-  [attributes addObject:NSAccessibilityEnabledAttribute];
-
-  return attributes;
-}
-
-- (NSArray*)accessibilityActionNames {
-  NSArray* parentActions = [super accessibilityActionNames];
-  return [parentActions arrayByAddingObject:NSAccessibilityPressAction];
-}
-
-- (id)accessibilityAttributeValue:(NSString*)attribute {
-  if ([attribute isEqual:NSAccessibilityRoleAttribute])
-    return NSAccessibilityButtonRole;
-
-  if ([attribute isEqual:NSAccessibilityRoleDescriptionAttribute])
-    return NSAccessibilityRoleDescription(NSAccessibilityButtonRole, nil);
-
-  if ([attribute isEqual:NSAccessibilityEnabledAttribute])
-    return [NSNumber numberWithBool:YES];
-
-  return [super accessibilityAttributeValue:attribute];
-}
-
-- (void)accessibilityPerformAction:(NSString*)action {
-  if ([action isEqual:NSAccessibilityPressAction]) {
-    [viewController_ itemSelected:self];
-    return;
-  }
-
-  [super accessibilityPerformAction:action];
-}
-
-- (NSColor*)highlightedMenuItemBackgroundColor {
-  ui::NativeTheme* nativeTheme = ui::NativeTheme::instance();
-  return gfx::SkColorToCalibratedNSColor(nativeTheme->GetSystemColor(
-      ui::NativeTheme::kColorId_FocusedMenuItemBackgroundColor));
-}
-
-@end
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
deleted file mode 100644
index 7399ac5..0000000
--- a/chrome/browser/ui/cocoa/location_bar/action_box_menu_bubble_controller_unittest.mm
+++ /dev/null
@@ -1,188 +0,0 @@
-// Copyright (c) 2010 The Chromium 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/location_bar/action_box_menu_bubble_controller.h"
-
-#include "base/command_line.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/values.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/ui/cocoa/cocoa_profile_test.h"
-#include "chrome/browser/ui/toolbar/action_box_menu_model.h"
-#include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/extension_builder.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace {
-
-const CGFloat kAnchorPointX = 400;
-const CGFloat kAnchorPointY = 300;
-
-class MenuDelegate : public ui::SimpleMenuModel::Delegate {
- public:
-  // Methods for determining the state of specific command ids.
-  virtual bool IsCommandIdChecked(int command_id) const OVERRIDE {
-    return false;
-  }
-
-  virtual bool IsCommandIdEnabled(int command_id) const OVERRIDE {
-    return true;
-  }
-
-  virtual bool GetAcceleratorForCommandId(
-      int command_id,
-      ui::Accelerator* accelerator) OVERRIDE {
-    return false;
-  }
-
-  // Performs the action associated with the specified command id.
-  virtual void ExecuteCommand(int command_id, int event_flags) OVERRIDE {
-  }
-};
-
-class ActionBoxMenuBubbleControllerTest : public CocoaProfileTest {
- public:
-  ActionBoxMenuBubbleControllerTest() {
-  }
-
-  virtual void SetUp() OVERRIDE {
-    CocoaProfileTest::SetUp();
-    ASSERT_TRUE(browser());
-
-    // Create a test extension service.
-    CommandLine command_line(CommandLine::NO_PROGRAM);
-    extensions::TestExtensionSystem* test_ext_system =
-        static_cast<extensions::TestExtensionSystem*>(
-                extensions::ExtensionSystem::Get(profile()));
-    service_ = test_ext_system->CreateExtensionService(
-        &command_line, base::FilePath(), false);
-    EXPECT_TRUE(service_->extensions_enabled());
-    service_->Init();
-  }
-
-  virtual void TearDown() OVERRIDE {
-    // Close our windows.
-    [controller_ close];
-    CocoaProfileTest::TearDown();
-  }
-
-  // Add an extension with a page_launcher to the model and the extension
-  // service. Call this before calling CreateController.
-  scoped_refptr<extensions::Extension> AddPageLauncherExtension(
-      ActionBoxMenuModel* model,
-      const std::string& page_launcher_title,
-      int command_id) {
-    scoped_refptr<extensions::Extension> extension =
-        extensions::ExtensionBuilder()
-        .SetManifest(extensions::DictionaryBuilder()
-                     .Set("name", "Extension with page launcher")
-                     .Set("version", "1.0.0")
-                     .Set("manifest_version", 2)
-                     .Set("page_launcher", extensions::DictionaryBuilder()
-                          .Set("default_title", page_launcher_title))
-                     .Set("app", extensions::DictionaryBuilder()
-                         .Set("background", extensions::DictionaryBuilder()
-                             .Set("page", ""))))
-        .Build();
-    service_->AddExtension(extension.get());
-    model->AddExtension(*extension.get(), command_id);
-    return extension;
-  }
-
-  // Creates a controller based on |model|. Takes ownership of |model|.
-  void CreateController(scoped_ptr<ActionBoxMenuModel> model) {
-    // The bubble controller will release itself when the window closes.
-    controller_ = [[ActionBoxMenuBubbleController alloc]
-         initWithModel:model.Pass()
-          parentWindow:test_window()
-            anchoredAt:NSMakePoint(kAnchorPointX, kAnchorPointY)
-               profile:profile()];
-
-    [controller_ showWindow:nil];
-  }
-
-  // Checks that the controller's view contains at least one separator subview
-  // and that it has full width.
-  void EnsureSeparatorHasCorrectWidth() {
-    bool found = false;
-    for (id view in [[[controller_ window] contentView] subviews]) {
-      // Assume all NSBox subviews are separators.
-      if ([view isKindOfClass:[NSBox class]]) {
-        found = true;
-        ASSERT_EQ(NSWidth([[controller_ window] frame]),
-                  NSWidth([view bounds]));
-      }
-    }
-    ASSERT_TRUE(found);
-  }
-
- protected:
-  ActionBoxMenuBubbleController* controller_;
-  MenuDelegate menu_delegate_;
-  ExtensionService* service_;
-};
-
-TEST_F(ActionBoxMenuBubbleControllerTest, CreateMenuWithExtensions) {
-  scoped_ptr<ActionBoxMenuModel> model(new ActionBoxMenuModel(
-      profile(), &menu_delegate_));
-  AddPageLauncherExtension(model.get(), "Launch extension 1", 0);
-  AddPageLauncherExtension(model.get(), "Launch extension 2", 1);
-  CreateController(model.Pass());
-
-  // Ensure extensions are there and in the right order.
-  int extension1Index = -1;
-  int extension2Index = -1;
-  for (id actionBoxMenuItemController in [controller_ items]) {
-    NSString* label = [[actionBoxMenuItemController nameField] stringValue];
-    int index = [actionBoxMenuItemController modelIndex];
-    NSImage* image = [[actionBoxMenuItemController iconView] image];
-    if ([label isEqualToString:@"Launch extension 1"]) {
-      ASSERT_EQ(-1, extension1Index);
-      ASSERT_EQ(19, [image size].width);
-      ASSERT_EQ(19, [image size].height);
-      extension1Index = index;
-    }
-    if ([label isEqualToString:@"Launch extension 2"]) {
-      ASSERT_EQ(-1, extension2Index);
-      ASSERT_EQ(19, [image size].width);
-      ASSERT_EQ(19, [image size].height);
-      extension2Index = index;
-    }
-  }
-
-  ASSERT_NE(-1, extension1Index);
-  ASSERT_NE(-1, extension2Index);
-  ASSERT_EQ(extension1Index, extension2Index - 1);
-}
-
-TEST_F(ActionBoxMenuBubbleControllerTest, CheckSeparatorWithShortExtensions) {
-  scoped_ptr<ActionBoxMenuModel> model(new ActionBoxMenuModel(
-      profile(), &menu_delegate_));
-  model->AddItem(0, ASCIIToUTF16("Bookmark this page"));
-  AddPageLauncherExtension(model.get(), "Short", 1);
-  CreateController(model.Pass());
-
-  // The width of the menu is dictated by the widest item which in this case
-  // is going to be "Bookmark this page", which comes before the separator.
-  // Ensure that, in this case, the separator has the full width.
-  EnsureSeparatorHasCorrectWidth();
-}
-
-TEST_F(ActionBoxMenuBubbleControllerTest, CheckSeparatorWithLongExtensions) {
-  scoped_ptr<ActionBoxMenuModel> model(new ActionBoxMenuModel(
-      profile(), &menu_delegate_));
-  model->AddItem(0, ASCIIToUTF16("Bookmark this page"));
-  AddPageLauncherExtension(model.get(),
-      "This is a long page launcher extension title...", 1);
-  CreateController(model.Pass());
-
-  // The width of the menu is dictated by the widest item which in this case
-  // is going to be the extension, which comes after the separator. Ensure that,
-  // in this case, the separator has the full width.
-  EnsureSeparatorHasCorrectWidth();
-}
-
-}  // namespace
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 69af462..d682305 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
@@ -28,7 +28,6 @@
 class LocationBarDecoration;
 class LocationIconDecoration;
 class PageActionDecoration;
-class PlusDecoration;
 class Profile;
 class SelectedKeywordDecoration;
 class StarDecoration;
@@ -77,7 +76,6 @@
   virtual ExtensionAction* GetPageAction(size_t index) OVERRIDE;
   virtual ExtensionAction* GetVisiblePageAction(size_t index) OVERRIDE;
   virtual void TestPageActionPressed(size_t index) OVERRIDE;
-  virtual void TestActionBoxMenuItemSelected(int command_id) OVERRIDE;
   virtual bool GetBookmarkStarVisibility() OVERRIDE;
 
   // Set/Get the editable state of the field.
@@ -87,10 +85,6 @@
   // Set the starred state of the bookmark star.
   void SetStarred(bool starred);
 
-  // Set (or resets) the icon image resource for the action box plus decoration.
-  void ResetActionBoxIcon();
-  void SetActionBoxIcon(int image_id);
-
   // Happens when the zoom changes for the active tab. |can_show_bubble| is
   // false when the change in zoom for the active tab wasn't an explicit user
   // action (e.g. switching tabs, creating a new tab, creating a new browser).
@@ -102,10 +96,6 @@
   // aim at.
   NSPoint GetBookmarkBubblePoint() const;
 
-  // Get the point in window coordinates on the Action Box icon for
-  // anchoring its bubbles.
-  NSPoint GetActionBoxAnchorPoint() const;
-
   // Get the point in window coordinates in the security icon at which the page
   // info bubble aims.
   NSPoint GetPageInfoBubblePoint() const;
@@ -211,9 +201,6 @@
   // Ensures the star decoration is visible or hidden, as required.
   void UpdateStarDecorationVisibility();
 
-  // Ensures the plus decoration is visible or hidden, as required.
-  void UpdatePlusDecorationVisibility();
-
   scoped_ptr<OmniboxViewMac> omnibox_view_;
 
   CommandUpdater* command_updater_;  // Weak, owned by Browser.
@@ -238,9 +225,6 @@
   // on the left.
   scoped_ptr<EVBubbleDecoration> ev_bubble_decoration_;
 
-  // Action "plus" button right of bookmark star.
-  scoped_ptr<PlusDecoration> plus_decoration_;
-
   // Bookmark star right of page actions.
   scoped_ptr<StarDecoration> star_decoration_;
 
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 8a7f095..ec510a6 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
@@ -39,7 +39,6 @@
 #import "chrome/browser/ui/cocoa/location_bar/keyword_hint_decoration.h"
 #import "chrome/browser/ui/cocoa/location_bar/location_icon_decoration.h"
 #import "chrome/browser/ui/cocoa/location_bar/page_action_decoration.h"
-#import "chrome/browser/ui/cocoa/location_bar/plus_decoration.h"
 #import "chrome/browser/ui/cocoa/location_bar/selected_keyword_decoration.h"
 #import "chrome/browser/ui/cocoa/location_bar/star_decoration.h"
 #import "chrome/browser/ui/cocoa/location_bar/zoom_decoration.h"
@@ -104,9 +103,6 @@
           content::PAGE_TRANSITION_TYPED |
           content::PAGE_TRANSITION_FROM_ADDRESS_BAR)),
       weak_ptr_factory_(this) {
-  if (extensions::FeatureSwitch::action_box()->IsEnabled()) {
-    plus_decoration_.reset(new PlusDecoration(this, browser_));
-  }
 
   for (size_t i = 0; i < CONTENT_SETTINGS_NUM_TYPES; ++i) {
     DCHECK_EQ(i, content_setting_decorations_.size());
@@ -238,7 +234,6 @@
   command_updater_->UpdateCommandEnabled(IDC_BOOKMARK_PAGE_FROM_STAR,
                                          IsStarEnabled());
   UpdateStarDecorationVisibility();
-  UpdatePlusDecorationVisibility();
   UpdateZoomDecoration();
   RefreshPageActionDecorations();
   RefreshContentSettingsDecorations();
@@ -467,11 +462,6 @@
     page_action_decorations_[index]->OnMousePressed(NSZeroRect);
 }
 
-void LocationBarViewMac::TestActionBoxMenuItemSelected(int command_id) {
-  plus_decoration_->action_box_button_controller()->ExecuteCommand(
-      command_id, 0);
-}
-
 bool LocationBarViewMac::GetBookmarkStarVisibility() {
   DCHECK(star_decoration_.get());
   return star_decoration_->IsVisible();
@@ -480,7 +470,6 @@
 void LocationBarViewMac::SetEditable(bool editable) {
   [field_ setEditable:editable ? YES : NO];
   UpdateStarDecorationVisibility();
-  UpdatePlusDecorationVisibility();
   UpdateZoomDecoration();
   UpdatePageActions();
   Layout();
@@ -504,16 +493,6 @@
   OnDecorationsChanged();
 }
 
-void LocationBarViewMac::ResetActionBoxIcon() {
-  plus_decoration_->ResetIcon();
-  OnDecorationsChanged();
-}
-
-void LocationBarViewMac::SetActionBoxIcon(int image_id) {
-  plus_decoration_->SetTemporaryIcon(image_id);
-  OnDecorationsChanged();
-}
-
 void LocationBarViewMac::ZoomChangedForActiveTab(bool can_show_bubble) {
   UpdateZoomDecoration();
   OnDecorationsChanged();
@@ -522,10 +501,6 @@
     zoom_decoration_->ToggleBubble(YES);
 }
 
-NSPoint LocationBarViewMac::GetActionBoxAnchorPoint() const {
-  return plus_decoration_->GetActionBoxAnchorPoint();
-}
-
 NSPoint LocationBarViewMac::GetBookmarkBubblePoint() const {
   AutocompleteTextFieldCell* cell = [field_ cell];
   const NSRect frame = [cell frameForDecoration:star_decoration_.get()
@@ -667,8 +642,6 @@
   [cell addLeftDecoration:location_icon_decoration_.get()];
   [cell addLeftDecoration:selected_keyword_decoration_.get()];
   [cell addLeftDecoration:ev_bubble_decoration_.get()];
-  if (plus_decoration_.get())
-    [cell addRightDecoration:plus_decoration_.get()];
   [cell addRightDecoration:star_decoration_.get()];
   [cell addRightDecoration:zoom_decoration_.get()];
 
@@ -704,7 +677,8 @@
     selected_keyword_decoration_->SetVisible(true);
     selected_keyword_decoration_->SetKeyword(short_name, is_extension_keyword);
     selected_keyword_decoration_->SetImage(GetKeywordImage(keyword));
-  } else if (toolbar_model_->GetSecurityLevel() == ToolbarModel::EV_SECURE) {
+  } else if (toolbar_model_->GetSecurityLevel(false) ==
+             ToolbarModel::EV_SECURE) {
     // Switch from location icon to show the EV bubble instead.
     location_icon_decoration_->SetVisible(false);
     ev_bubble_decoration_->SetVisible(true);
@@ -748,17 +722,5 @@
 }
 
 void LocationBarViewMac::UpdateStarDecorationVisibility() {
-  // If the action box is enabled, only show the star if it's lit.
-  bool visible = IsStarEnabled();
-  if (!star_decoration_->starred() &&
-      extensions::FeatureSwitch::action_box()->IsEnabled())
-    visible = false;
-  star_decoration_->SetVisible(visible);
-}
-
-void LocationBarViewMac::UpdatePlusDecorationVisibility() {
-  if (extensions::FeatureSwitch::action_box()->IsEnabled()) {
-    // If the action box is enabled, hide it when input is in progress.
-    plus_decoration_->SetVisible(!toolbar_model_->GetInputInProgress());
-  }
+  star_decoration_->SetVisible(IsStarEnabled());
 }
diff --git a/chrome/browser/ui/cocoa/location_bar/plus_decoration.h b/chrome/browser/ui/cocoa/location_bar/plus_decoration.h
deleted file mode 100644
index 64bcf70..0000000
--- a/chrome/browser/ui/cocoa/location_bar/plus_decoration.h
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_COCOA_LOCATION_BAR_PLUS_DECORATION_H_
-#define CHROME_BROWSER_UI_COCOA_LOCATION_BAR_PLUS_DECORATION_H_
-
-#import <Cocoa/Cocoa.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"
-
-@class ActionBoxMenuBubbleController;
-class Browser;
-class LocationBarViewMac;
-
-// Note: this file is under development (see crbug.com/138118).
-
-// Plus icon on the right side of the location bar.
-class PlusDecoration : public ButtonDecoration,
-                       public ActionBoxButtonController::Delegate {
- public:
-  PlusDecoration(LocationBarViewMac* owner, Browser* browser);
-  virtual ~PlusDecoration();
-
-  // Helper to get where the action box menu and bubble point should be
-  // anchored. Similar to |PageActionDecoration| or |StarDecoration|.
-  NSPoint GetActionBoxAnchorPoint();
-
-  // Sets or clears a temporary icon for the button.
-  void ResetIcon();
-  void SetTemporaryIcon(int image_id);
-
-  // Implement |LocationBarDecoration|.
-  virtual bool AcceptsMousePress() OVERRIDE;
-  virtual bool OnMousePressed(NSRect frame) OVERRIDE;
-  virtual NSString* GetToolTip() OVERRIDE;
-
-  ActionBoxButtonController* action_box_button_controller() {
-    return &controller_;
-  }
-
- private:
-  // Implement |ActionBoxButtonController::Delegate|.
-  virtual void ShowMenu(scoped_ptr<ActionBoxMenuModel> model) OVERRIDE;
-
-  // Owner of the decoration, used to obtain the menu.
-  LocationBarViewMac* owner_;
-
-  Browser* browser_;
-
-  ActionBoxButtonController controller_;
-
-  void SetIcons(int normal_id, int hover_id, int pressed_id);
-
-  base::scoped_nsobject<ActionBoxMenuBubbleController> menu_controller_;
-
-  DISALLOW_COPY_AND_ASSIGN(PlusDecoration);
-};
-
-#endif  // CHROME_BROWSER_UI_COCOA_LOCATION_BAR_PLUS_DECORATION_H_
diff --git a/chrome/browser/ui/cocoa/location_bar/plus_decoration.mm b/chrome/browser/ui/cocoa/location_bar/plus_decoration.mm
deleted file mode 100644
index c8cb131..0000000
--- a/chrome/browser/ui/cocoa/location_bar/plus_decoration.mm
+++ /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.
-
-#import "chrome/browser/ui/cocoa/location_bar/plus_decoration.h"
-
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_window.h"
-#import "chrome/browser/ui/cocoa/location_bar/action_box_menu_bubble_controller.h"
-#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.h"
-#import "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h"
-#import "chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.h"
-#include "chrome/browser/ui/toolbar/action_box_menu_model.h"
-#include "grit/generated_resources.h"
-#include "grit/theme_resources.h"
-#include "ui/base/l10n/l10n_util_mac.h"
-
-namespace {
-// The offset to apply to the menu so that it appears just attached to the
-// right-hand side of the omnibox while slightly overlapping vertically.
-const CGFloat kAnchorPointXOffset = 1.0;
-const CGFloat kAnchorPointYOffset = 2.0;
-}  // namespace
-
-PlusDecoration::PlusDecoration(LocationBarViewMac* owner,
-                               Browser* browser)
-    : owner_(owner),
-      browser_(browser),
-      controller_(browser, this) {
-  SetVisible(true);
-  ResetIcon();
-}
-
-PlusDecoration::~PlusDecoration() {
-}
-
-NSPoint PlusDecoration::GetActionBoxAnchorPoint() {
-  AutocompleteTextField* field = owner_->GetAutocompleteTextField();
-  NSRect bounds = [field bounds];
-  NSPoint anchor = NSMakePoint(NSMaxX(bounds) - kAnchorPointXOffset,
-                               NSMaxY(bounds) - kAnchorPointYOffset);
-  return [field convertPoint:anchor toView:nil];
-}
-
-void PlusDecoration::ResetIcon() {
-  SetIcons(
-      IDR_ACTION_BOX_BUTTON_NORMAL,
-      IDR_ACTION_BOX_BUTTON_HOVER,
-      IDR_ACTION_BOX_BUTTON_PRESSED);
-}
-
-void PlusDecoration::SetTemporaryIcon(int image_id) {
-  SetIcons(image_id, image_id, image_id);
-}
-
-bool PlusDecoration::AcceptsMousePress() {
-  return true;
-}
-
-bool PlusDecoration::OnMousePressed(NSRect frame) {
-  controller_.OnButtonClicked();
-  return true;
-}
-
-NSString* PlusDecoration::GetToolTip() {
-  return l10n_util::GetNSStringWithFixup(IDS_TOOLTIP_ACTION_BOX_BUTTON);
-}
-
-void PlusDecoration::ShowMenu(scoped_ptr<ActionBoxMenuModel> menu_model) {
-  // Controller for the menu attached to the plus decoration.
-  // |menu_controller| will automatically release itself on close.
-  NSWindow* parent = browser_->window()->GetNativeWindow();
-  ActionBoxMenuBubbleController* menu_controller =
-      [[ActionBoxMenuBubbleController alloc]
-          initWithModel:menu_model.Pass()
-           parentWindow:parent
-             anchoredAt:[parent convertBaseToScreen:GetActionBoxAnchorPoint()]
-                profile:browser_->profile()];
-
-  [menu_controller showWindow:nil];
-}
-
-void PlusDecoration::SetIcons(int normal_id, int hover_id, int pressed_id) {
-  SetNormalImage(OmniboxViewMac::ImageForResource(normal_id));
-  SetHoverImage(OmniboxViewMac::ImageForResource(hover_id));
-  SetPressedImage(OmniboxViewMac::ImageForResource(pressed_id));
-}
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.mm b/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.mm
index e0bc46d..de73f1e 100644
--- a/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.mm
+++ b/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.mm
@@ -465,7 +465,7 @@
   // [Could it be to not change if no change?  If so, I'm guessing
   // AppKit may already handle that.]
   const ToolbarModel::SecurityLevel security_level =
-      toolbar_model()->GetSecurityLevel();
+      toolbar_model()->GetSecurityLevel(false);
 
   // Emphasize the scheme for security UI display purposes (if necessary).
   if (!model()->user_input_in_progress() && model()->CurrentTextIsURL() &&
@@ -867,7 +867,7 @@
 // this method could call the OmniboxView version.
 bool OmniboxViewMac::ShouldEnableCopyURL() {
   return !model()->user_input_in_progress() &&
-      toolbar_model()->WouldReplaceSearchURLWithSearchTerms();
+      toolbar_model()->WouldReplaceSearchURLWithSearchTerms(false);
 }
 
 bool OmniboxViewMac::CanPasteAndGo() {
diff --git a/chrome/browser/ui/cocoa/run_loop_testing.mm b/chrome/browser/ui/cocoa/run_loop_testing.mm
index f79aa53..927e440 100644
--- a/chrome/browser/ui/cocoa/run_loop_testing.mm
+++ b/chrome/browser/ui/cocoa/run_loop_testing.mm
@@ -7,6 +7,7 @@
 #import <Foundation/Foundation.h>
 
 #include "base/mac/scoped_nsobject.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/message_loop/message_pump_mac.h"
 
 // This class is scheduled with a delayed selector to quit the message pump.
@@ -37,7 +38,7 @@
 namespace testing {
 
 void NSRunLoopRunAllPending() {
-  scoped_refptr<base::MessagePumpNSRunLoop> message_pump(
+  scoped_ptr<base::MessagePumpNSRunLoop> message_pump(
       new base::MessagePumpNSRunLoop);
 
   // Put a delayed selector on the queue. All other pending delayed selectors
diff --git a/chrome/browser/ui/cocoa/status_icons/status_tray_mac.h b/chrome/browser/ui/cocoa/status_icons/status_tray_mac.h
index 34aac19..2bb19c4 100644
--- a/chrome/browser/ui/cocoa/status_icons/status_tray_mac.h
+++ b/chrome/browser/ui/cocoa/status_icons/status_tray_mac.h
@@ -14,7 +14,7 @@
 
  protected:
   // Factory method for creating a status icon.
-  virtual StatusIcon* CreatePlatformStatusIcon() OVERRIDE;
+  virtual StatusIcon* CreatePlatformStatusIcon(StatusIconType type) OVERRIDE;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(StatusTrayMac);
diff --git a/chrome/browser/ui/cocoa/status_icons/status_tray_mac.mm b/chrome/browser/ui/cocoa/status_icons/status_tray_mac.mm
index 5d6c3e2..7a4324d 100644
--- a/chrome/browser/ui/cocoa/status_icons/status_tray_mac.mm
+++ b/chrome/browser/ui/cocoa/status_icons/status_tray_mac.mm
@@ -13,6 +13,6 @@
 StatusTrayMac::StatusTrayMac() {
 }
 
-StatusIcon* StatusTrayMac::CreatePlatformStatusIcon() {
+StatusIcon* StatusTrayMac::CreatePlatformStatusIcon(StatusIconType type) {
   return new StatusIconMac();
 }
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 0ead38a..85aea22 100644
--- a/chrome/browser/ui/cocoa/tab_modal_confirm_dialog_mac.h
+++ b/chrome/browser/ui/cocoa/tab_modal_confirm_dialog_mac.h
@@ -38,8 +38,9 @@
   virtual void AcceptTabModalDialog() OVERRIDE;
   virtual void CancelTabModalDialog() OVERRIDE;
 
-  // TabModalConfirmDialogCloseDelegate:
+  // TabModalConfirmDialogOperationsDelegate:
   virtual void CloseDialog() OVERRIDE;
+  virtual void SetPreventCloseOnLoadStart(bool prevent) OVERRIDE;
 
   // ConstrainedWindowMacDelegate:
   virtual void OnConstrainedWindowClosed(
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 bdca853..6966adc 100644
--- a/chrome/browser/ui/cocoa/tab_modal_confirm_dialog_mac.mm
+++ b/chrome/browser/ui/cocoa/tab_modal_confirm_dialog_mac.mm
@@ -88,7 +88,7 @@
       [[CustomConstrainedWindowSheet alloc]
           initWithCustomWindow:[alert_ window]]);
   window_.reset(new ConstrainedWindowMac(this, web_contents, sheet));
-  delegate_->set_close_delegate(this);
+  delegate_->set_operations_delegate(this);
 }
 
 TabModalConfirmDialogMac::~TabModalConfirmDialogMac() {
@@ -106,7 +106,14 @@
   window_->CloseWebContentsModalDialog();
 }
 
+void TabModalConfirmDialogMac::SetPreventCloseOnLoadStart(bool prevent) {
+  window_->SetPreventCloseOnLoadStart(prevent);
+}
+
 void TabModalConfirmDialogMac::OnConstrainedWindowClosed(
     ConstrainedWindowMac* window) {
+  // Provide a disposition in case the dialog was closed without accepting or
+  // cancelling.
+  delegate_->Cancel();
   delete this;
 }
diff --git a/chrome/browser/ui/cocoa/tabs/tab_strip_view.mm b/chrome/browser/ui/cocoa/tabs/tab_strip_view.mm
index 9748eb0..e62eb67 100644
--- a/chrome/browser/ui/cocoa/tabs/tab_strip_view.mm
+++ b/chrome/browser/ui/cocoa/tabs/tab_strip_view.mm
@@ -56,7 +56,9 @@
   if (NSMinY(dirtyRect) < backgroundHeight) {
     gfx::ScopedNSGraphicsContextSaveGState scopedGState;
     NSGraphicsContext *context = [NSGraphicsContext currentContext];
-    [context cr_setPatternPhase:[[self window] themePatternPhase] forView:self];
+    NSPoint phase = [[self window] themePatternPhaseForAlignment:
+        THEME_PATTERN_ALIGN_WITH_TAB_STRIP];
+    [context cr_setPatternPhase:phase forView:self];
 
     // Themes don't have an inactive image so only look for one if there's no
     // theme.
diff --git a/chrome/browser/ui/cocoa/tabs/tab_view.mm b/chrome/browser/ui/cocoa/tabs/tab_view.mm
index d7ff32f..99985d9 100644
--- a/chrome/browser/ui/cocoa/tabs/tab_view.mm
+++ b/chrome/browser/ui/cocoa/tabs/tab_view.mm
@@ -301,6 +301,21 @@
       bitmapResources[active][selected], true);
 }
 
+// Draws the active tab background.
+- (void)drawFillForActiveTab:(NSRect)dirtyRect {
+  NSColor* backgroundImageColor = [self backgroundColorForSelected:YES];
+  [backgroundImageColor set];
+
+  // Themes can have partially transparent images. NSRectFill() is measurably
+  // faster though, so call it for the known-safe default theme.
+  ThemeService* themeProvider =
+      static_cast<ThemeService*>([[self window] themeProvider]);
+  if (themeProvider && themeProvider->UsingDefaultTheme())
+    NSRectFill(dirtyRect);
+  else
+    NSRectFillUsingOperation(dirtyRect, NSCompositeSourceOver);
+}
+
 // Draws the tab background.
 - (void)drawFill:(NSRect)dirtyRect {
   gfx::ScopedNSGraphicsContextSaveGState scopedGState;
@@ -309,65 +324,51 @@
 
   ThemeService* themeProvider =
       static_cast<ThemeService*>([[self window] themeProvider]);
-  [context cr_setPatternPhase:[[self window] themePatternPhase] forView:self];
-
+  NSPoint phase = [[self window]
+      themePatternPhaseForAlignment: THEME_PATTERN_ALIGN_WITH_TAB_STRIP];
+  [context cr_setPatternPhase:phase forView:self];
 
   CGImageRef mask([self tabClippingMask]);
   CGRect maskBounds = CGRectMake(0, 0, maskCacheWidth_, kMaskHeight);
   CGContextClipToMask(cgContext, maskBounds, mask);
 
   bool selected = [self state];
+  if (selected) {
+    [self drawFillForActiveTab:dirtyRect];
+    return;
+  }
 
   // Background tabs should not paint over the tab strip separator, which is
   // two pixels high in both lodpi and hidpi.
-  if (!selected && dirtyRect.origin.y < 1)
+  if (dirtyRect.origin.y < 1)
     dirtyRect.origin.y = 2 * [self cr_lineWidth];
 
+  // Draw the tab background.
+  NSColor* backgroundImageColor = [self backgroundColorForSelected:NO];
+  [backgroundImageColor set];
+
+  // Themes can have partially transparent images. NSRectFill() is measurably
+  // faster though, so call it for the known-safe default theme.
   bool usingDefaultTheme = themeProvider && themeProvider->UsingDefaultTheme();
-  NSColor* backgroundImageColor = [self backgroundColorForSelected:selected];
+  if (usingDefaultTheme)
+    NSRectFill(dirtyRect);
+  else
+    NSRectFillUsingOperation(dirtyRect, NSCompositeSourceOver);
 
-  // Don't draw the window/tab bar background when selected, since the tab
-  // background overlay drawn over it (see below) will be fully opaque.
-  if (!selected) {
-    [backgroundImageColor set];
-    // Themes can have partially transparent images. NSRectFill() is measurably
-    // faster though, so call it for the known-safe default theme.
-    if (usingDefaultTheme)
-      NSRectFill(dirtyRect);
-    else
-      NSRectFillUsingOperation(dirtyRect, NSCompositeSourceOver);
-  }
-
-  // Use the same overlay for the selected state and for hover and alert
-  // glows; for the selected state, it's fully opaque.
+  // Draw the glow for hover and the overlay for alerts.
   CGFloat hoverAlpha = [self hoverAlpha];
   CGFloat alertAlpha = [self alertAlpha];
-  if (selected || hoverAlpha > 0 || alertAlpha > 0) {
+  if (hoverAlpha > 0 || alertAlpha > 0) {
     gfx::ScopedNSGraphicsContextSaveGState contextSave;
-
-    // Draw the selected background / glow overlay.
     CGContextBeginTransparencyLayer(cgContext, 0);
-    if (!selected) {
-      // The alert glow overlay is like the selected state but at most at most
-      // 80% opaque. The hover glow brings up the overlay's opacity at most
-      // 50%.
-      CGFloat backgroundAlpha = 0.8 * alertAlpha;
-      backgroundAlpha += (1 - backgroundAlpha) * 0.5 * hoverAlpha;
-      CGContextSetAlpha(cgContext, backgroundAlpha);
-    }
 
-    // For background tabs, this branch is taken to draw a highlight. The
-    // highlight is drawn using the foreground tab bitmap.
-    if (!selected && themeProvider)
-      backgroundImageColor = [self backgroundColorForSelected:YES];
+    // The alert glow overlay is like the selected state but at most at most 80%
+    // opaque. The hover glow brings up the overlay's opacity at most 50%.
+    CGFloat backgroundAlpha = 0.8 * alertAlpha;
+    backgroundAlpha += (1 - backgroundAlpha) * 0.5 * hoverAlpha;
+    CGContextSetAlpha(cgContext, backgroundAlpha);
 
-    [backgroundImageColor set];
-    // Themes can have partially transparent images. NSRectFill() is measurably
-    // faster though, so call it for the known-safe default theme.
-    if (usingDefaultTheme)
-      NSRectFill(dirtyRect);
-    else
-      NSRectFillUsingOperation(dirtyRect, NSCompositeSourceOver);
+    [self drawFillForActiveTab:dirtyRect];
 
     // ui::ThemeProvider::HasCustomImage is true only if the theme provides the
     // image. However, even if the theme doesn't provide a tab background, the
@@ -377,7 +378,7 @@
         (themeProvider->HasCustomImage(IDR_THEME_TAB_BACKGROUND) ||
          themeProvider->HasCustomImage(IDR_THEME_FRAME));
     // Draw a mouse hover gradient for the default themes.
-    if (!selected && hoverAlpha > 0) {
+    if (hoverAlpha > 0) {
       if (themeProvider && !hasCustomTheme) {
         base::scoped_nsobject<NSGradient> glow([NSGradient alloc]);
         [glow initWithStartingColor:[NSColor colorWithCalibratedWhite:1.0
diff --git a/chrome/browser/ui/cocoa/tabs/tab_window_controller.mm b/chrome/browser/ui/cocoa/tabs/tab_window_controller.mm
index e49c875..7978772 100644
--- a/chrome/browser/ui/cocoa/tabs/tab_window_controller.mm
+++ b/chrome/browser/ui/cocoa/tabs/tab_window_controller.mm
@@ -33,9 +33,11 @@
   return NO;
 }
 
-- (NSPoint)themePatternPhase {
-  if ([self parentWindow])
-    return [[[self parentWindow] windowController] themePatternPhase];
+- (NSPoint)themePatternPhaseForAlignment:(ThemePatternAlignment)alignment {
+  if ([self parentWindow]) {
+    return [[[self parentWindow] windowController]
+        themePatternPhaseForAlignment:alignment];
+  }
   return NSZeroPoint;
 }
 
diff --git a/chrome/browser/ui/cocoa/themed_window.h b/chrome/browser/ui/cocoa/themed_window.h
index c35db6d..f553795 100644
--- a/chrome/browser/ui/cocoa/themed_window.h
+++ b/chrome/browser/ui/cocoa/themed_window.h
@@ -21,12 +21,22 @@
 };
 typedef NSUInteger ThemedWindowStyle;
 
+// Indicates how the theme image should be aligned.
+enum ThemePatternAlignment {
+  // Aligns the top of the theme image with the top of the frame. Use this
+  // for IDR_THEME_THEME_FRAME.*
+  THEME_PATTERN_ALIGN_WITH_FRAME,
+  // Aligns the top of the theme image with the top of the tab
+  // strip. Use this for IDR_THEME_TAB_BACKGROUND and IDR_THEME_TOOLBAR.
+  THEME_PATTERN_ALIGN_WITH_TAB_STRIP
+};
+
 // Implemented by windows that support theming.
 
 @interface NSWindow (ThemeProvider)
 - (ThemeProvider*)themeProvider;
 - (ThemedWindowStyle)themedWindowStyle;
-- (NSPoint)themePatternPhase;
+- (NSPoint)themePatternPhaseForAlignment:(ThemePatternAlignment)alignment;
 @end
 
 #endif  // CHROME_BROWSER_UI_COCOA_THEMED_WINDOW_H_
diff --git a/chrome/browser/ui/cocoa/themed_window.mm b/chrome/browser/ui/cocoa/themed_window.mm
index 911bf8a..6696464 100644
--- a/chrome/browser/ui/cocoa/themed_window.mm
+++ b/chrome/browser/ui/cocoa/themed_window.mm
@@ -16,7 +16,7 @@
   return THEMED_NORMAL;
 }
 
-- (NSPoint)themePatternPhase {
+- (NSPoint)themePatternPhaseForAlignment:(ThemePatternAlignment)alignment {
   return NSZeroPoint;
 }
 
diff --git a/chrome/browser/ui/cocoa/toolbar/toolbar_view.mm b/chrome/browser/ui/cocoa/toolbar/toolbar_view.mm
index 5b9cb46..a4ec3fd 100644
--- a/chrome/browser/ui/cocoa/toolbar/toolbar_view.mm
+++ b/chrome/browser/ui/cocoa/toolbar/toolbar_view.mm
@@ -18,9 +18,8 @@
 }
 
 - (void)drawRect:(NSRect)rect {
-  // The toolbar's background pattern is phased relative to the
-  // tab strip view's background pattern.
-  NSPoint phase = [[self window] themePatternPhase];
+  NSPoint phase = [[self window]
+      themePatternPhaseForAlignment:THEME_PATTERN_ALIGN_WITH_TAB_STRIP];
   [[NSGraphicsContext currentContext] cr_setPatternPhase:phase forView:self];
   [self drawBackgroundWithOpaque:YES];
 }
diff --git a/chrome/browser/ui/collected_cookies_infobar_delegate.cc b/chrome/browser/ui/collected_cookies_infobar_delegate.cc
index e335e4d..b60761e 100644
--- a/chrome/browser/ui/collected_cookies_infobar_delegate.cc
+++ b/chrome/browser/ui/collected_cookies_infobar_delegate.cc
@@ -11,6 +11,7 @@
 #include "grit/theme_resources.h"
 #include "ui/base/l10n/l10n_util.h"
 
+
 // static
 void CollectedCookiesInfoBarDelegate::Create(InfoBarService* infobar_service) {
   infobar_service->AddInfoBar(scoped_ptr<InfoBarDelegate>(
diff --git a/chrome/browser/ui/collected_cookies_infobar_delegate.h b/chrome/browser/ui/collected_cookies_infobar_delegate.h
index 2c0e1a7..2023026 100644
--- a/chrome/browser/ui/collected_cookies_infobar_delegate.h
+++ b/chrome/browser/ui/collected_cookies_infobar_delegate.h
@@ -16,7 +16,8 @@
 // the reload right from the infobar.
 class CollectedCookiesInfoBarDelegate : public ConfirmInfoBarDelegate {
  public:
-  // Creates a collected cookies delegate and adds it to |infobar_service|.
+  // Creates a collected cookies infobar delegate and adds it to
+  // |infobar_service|.
   static void Create(InfoBarService* infobar_service);
 
  private:
diff --git a/chrome/browser/ui/content_settings/content_setting_bubble_model.cc b/chrome/browser/ui/content_settings/content_setting_bubble_model.cc
index d73ffb3..b2bd578 100644
--- a/chrome/browser/ui/content_settings/content_setting_bubble_model.cc
+++ b/chrome/browser/ui/content_settings/content_setting_bubble_model.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/ui/content_settings/content_setting_bubble_model.h"
 
+#include "base/command_line.h"
 #include "base/prefs/pref_service.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/chrome_notification_types.h"
@@ -19,9 +20,12 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/blocked_content/blocked_content_tab_helper.h"
 #include "chrome/browser/ui/blocked_content/blocked_content_tab_helper_delegate.h"
+#include "chrome/browser/ui/blocked_content/popup_blocker_tab_helper.h"
+#include "chrome/browser/ui/browser_navigator.h"
 #include "chrome/browser/ui/collected_cookies_infobar_delegate.h"
 #include "chrome/browser/ui/content_settings/content_setting_bubble_model_delegate.h"
 #include "chrome/browser/ui/content_settings/content_setting_changed_infobar_delegate.h"
+#include "chrome/common/chrome_switches.h"
 #include "chrome/common/content_settings.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/render_messages.h"
@@ -33,8 +37,10 @@
 #include "content/public/browser/web_contents_delegate.h"
 #include "grit/generated_resources.h"
 #include "grit/theme_resources.h"
+#include "grit/ui_resources.h"
 #include "net/base/net_util.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "ui/base/resource/resource_bundle.h"
 
 using content::UserMetricsAction;
 using content::WebContents;
@@ -454,7 +460,7 @@
 
 ContentSettingCookiesBubbleModel::~ContentSettingCookiesBubbleModel() {
   // On some plattforms e.g. MacOS X it is possible to close a tab while the
-  // cookies settubgs bubble is open. This resets the web contents to NULL.
+  // cookies settings bubble is open. This resets the web contents to NULL.
   if (settings_changed() && web_contents()) {
     CollectedCookiesInfoBarDelegate::Create(
         InfoBarService::FromWebContents(web_contents()));
@@ -539,6 +545,29 @@
 
 
 void ContentSettingPopupBubbleModel::SetPopups() {
+  if (CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kEnableBetterPopupBlocking)) {
+    IDMap<chrome::NavigateParams, IDMapOwnPointer>& blocked_popups =
+        PopupBlockerTabHelper::FromWebContents(web_contents())
+            ->GetBlockedPopupRequests();
+    for (IDMap<chrome::NavigateParams, IDMapOwnPointer>::const_iterator
+             iter(&blocked_popups);
+         !iter.IsAtEnd();
+         iter.Advance()) {
+
+      std::string title(iter.GetCurrentValue()->url.spec());
+      // The popup may not have a valid URL.
+      if (title.empty())
+        title = l10n_util::GetStringUTF8(IDS_TAB_LOADING_TITLE);
+      PopupItem popup_item(
+          ui::ResourceBundle::GetSharedInstance().GetImageNamed(
+              IDR_DEFAULT_FAVICON),
+          title,
+          iter.GetCurrentKey());
+      add_popup(popup_item);
+    }
+    return;
+  }
   std::vector<WebContents*> blocked_contents;
   BlockedContentTabHelper::FromWebContents(web_contents())->
       GetBlockedContents(&blocked_contents);
@@ -549,18 +578,22 @@
     // have a URL or title.
     if (title.empty())
       title = l10n_util::GetStringUTF8(IDS_TAB_LOADING_TITLE);
-    PopupItem popup_item;
-    popup_item.title = title;
-    popup_item.image = FaviconTabHelper::FromWebContents(*i)->GetFavicon();
-    popup_item.web_contents = *i;
+    PopupItem popup_item(
+        FaviconTabHelper::FromWebContents(*i)->GetFavicon(), title, *i);
     add_popup(popup_item);
   }
 }
 
 void ContentSettingPopupBubbleModel::OnPopupClicked(int index) {
   if (web_contents()) {
-    BlockedContentTabHelper::FromWebContents(web_contents())->
-        LaunchForContents(bubble_content().popup_items[index].web_contents);
+    if (CommandLine::ForCurrentProcess()->HasSwitch(
+            switches::kEnableBetterPopupBlocking)) {
+      PopupBlockerTabHelper::FromWebContents(web_contents())->
+          ShowBlockedPopup(bubble_content().popup_items[index].popup_id);
+    } else {
+      BlockedContentTabHelper::FromWebContents(web_contents())->
+          LaunchForContents(bubble_content().popup_items[index].web_contents);
+    }
   }
 }
 
@@ -920,11 +953,11 @@
 void ContentSettingDomainListBubbleModel::SetDomainsAndCustomLink() {
   TabSpecificContentSettings* content_settings =
       TabSpecificContentSettings::FromWebContents(web_contents());
-  const GeolocationSettingsState& settings =
-      content_settings->geolocation_settings_state();
-  GeolocationSettingsState::FormattedHostsPerState formatted_hosts_per_state;
+  const ContentSettingsUsagesState& usages =
+      content_settings->geolocation_usages_state();
+  ContentSettingsUsagesState::FormattedHostsPerState formatted_hosts_per_state;
   unsigned int tab_state_flags = 0;
-  settings.GetDetailedInfo(&formatted_hosts_per_state, &tab_state_flags);
+  usages.GetDetailedInfo(&formatted_hosts_per_state, &tab_state_flags);
   // Divide the tab's current geolocation users into sets according to their
   // permission state.
   MaybeAddDomainList(formatted_hosts_per_state[CONTENT_SETTING_ALLOW],
@@ -933,12 +966,12 @@
   MaybeAddDomainList(formatted_hosts_per_state[CONTENT_SETTING_BLOCK],
                      IDS_GEOLOCATION_BUBBLE_SECTION_DENIED);
 
-  if (tab_state_flags & GeolocationSettingsState::TABSTATE_HAS_EXCEPTION) {
+  if (tab_state_flags & ContentSettingsUsagesState::TABSTATE_HAS_EXCEPTION) {
     set_custom_link(l10n_util::GetStringUTF8(
         IDS_GEOLOCATION_BUBBLE_CLEAR_LINK));
     set_custom_link_enabled(true);
   } else if (tab_state_flags &
-             GeolocationSettingsState::TABSTATE_HAS_CHANGED) {
+             ContentSettingsUsagesState::TABSTATE_HAS_CHANGED) {
     set_custom_link(l10n_util::GetStringUTF8(
         IDS_GEOLOCATION_BUBBLE_REQUIRE_RELOAD_TO_CLEAR));
   }
@@ -952,12 +985,12 @@
   const GURL& embedder_url = web_contents()->GetURL();
   TabSpecificContentSettings* content_settings =
       TabSpecificContentSettings::FromWebContents(web_contents());
-  const GeolocationSettingsState::StateMap& state_map =
-      content_settings->geolocation_settings_state().state_map();
+  const ContentSettingsUsagesState::StateMap& state_map =
+      content_settings->geolocation_usages_state().state_map();
   HostContentSettingsMap* settings_map =
       profile()->GetHostContentSettingsMap();
 
-  for (GeolocationSettingsState::StateMap::const_iterator it =
+  for (ContentSettingsUsagesState::StateMap::const_iterator it =
        state_map.begin(); it != state_map.end(); ++it) {
     settings_map->SetContentSetting(
         ContentSettingsPattern::FromURLNoWildcard(it->first),
diff --git a/chrome/browser/ui/content_settings/content_setting_bubble_model.h b/chrome/browser/ui/content_settings/content_setting_bubble_model.h
index fbb19c1..89c7bef 100644
--- a/chrome/browser/ui/content_settings/content_setting_bubble_model.h
+++ b/chrome/browser/ui/content_settings/content_setting_bubble_model.h
@@ -34,9 +34,20 @@
   typedef ContentSettingBubbleModelDelegate Delegate;
 
   struct PopupItem {
+    PopupItem(const gfx::Image& image,
+              const std::string& title,
+              content::WebContents* web_contents)
+        : image(image),
+          title(title),
+          web_contents(web_contents),
+          popup_id(-1) {}
+    PopupItem(const gfx::Image& image, const std::string& title, int32 popup_id)
+        : image(image), title(title), web_contents(NULL), popup_id(popup_id) {}
+
     gfx::Image image;
     std::string title;
     content::WebContents* web_contents;
+    int32 popup_id;
   };
   typedef std::vector<PopupItem> PopupItems;
 
diff --git a/chrome/browser/ui/content_settings/content_setting_image_model.cc b/chrome/browser/ui/content_settings/content_setting_image_model.cc
index 97e881a..c49163b 100644
--- a/chrome/browser/ui/content_settings/content_setting_image_model.cc
+++ b/chrome/browser/ui/content_settings/content_setting_image_model.cc
@@ -174,18 +174,18 @@
       TabSpecificContentSettings::FromWebContents(web_contents);
   if (!content_settings)
     return;
-  const GeolocationSettingsState& settings_state = content_settings->
-      geolocation_settings_state();
-  if (settings_state.state_map().empty())
+  const ContentSettingsUsagesState& usages_state = content_settings->
+      geolocation_usages_state();
+  if (usages_state.state_map().empty())
     return;
   set_visible(true);
 
   // If any embedded site has access the allowed icon takes priority over the
   // blocked icon.
-  unsigned int tab_state_flags = 0;
-  settings_state.GetDetailedInfo(NULL, &tab_state_flags);
+  unsigned int state_flags = 0;
+  usages_state.GetDetailedInfo(NULL, &state_flags);
   bool allowed =
-      !!(tab_state_flags & GeolocationSettingsState::TABSTATE_HAS_ANY_ALLOWED);
+      !!(state_flags & ContentSettingsUsagesState::TABSTATE_HAS_ANY_ALLOWED);
   set_icon(allowed ? IDR_ALLOWED_LOCATION : IDR_BLOCKED_LOCATION);
   set_tooltip(l10n_util::GetStringUTF8(allowed ?
       IDS_GEOLOCATION_ALLOWED_TOOLTIP : IDS_GEOLOCATION_BLOCKED_TOOLTIP));
diff --git a/chrome/browser/ui/extensions/extension_install_ui_default.cc b/chrome/browser/ui/extensions/extension_install_ui_default.cc
index 54e6a8a..abc00b6 100644
--- a/chrome/browser/ui/extensions/extension_install_ui_default.cc
+++ b/chrome/browser/ui/extensions/extension_install_ui_default.cc
@@ -82,7 +82,7 @@
 // Helper class to put up an infobar when installation fails.
 class ErrorInfoBarDelegate : public ConfirmInfoBarDelegate {
  public:
-  // Creates an error delegate and adds it to |infobar_service|.
+  // Creates an error infobar delegate and adds it to |infobar_service|.
   static void Create(InfoBarService* infobar_service,
                      const extensions::CrxInstallerError& error);
 
@@ -155,7 +155,7 @@
 void ExtensionInstallUI::OpenAppInstalledUI(Profile* profile,
                                             const std::string& app_id) {
 #if defined(OS_CHROMEOS)
-  AppListService::Get()->ShowAppList(profile);
+  AppListService::Get()->ShowForProfile(profile);
 
   content::NotificationService::current()->Notify(
       chrome::NOTIFICATION_APP_INSTALLED_TO_APPLIST,
@@ -255,7 +255,7 @@
 #endif
 
     if (apps::IsAppLauncherEnabled()) {
-      AppListService::Get()->ShowAppList(current_profile);
+      AppListService::Get()->ShowForProfile(current_profile);
 
       content::NotificationService::current()->Notify(
           chrome::NOTIFICATION_APP_INSTALLED_TO_APPLIST,
@@ -284,7 +284,7 @@
 
   Browser* browser = chrome::FindLastActiveWithProfile(profile_,
       chrome::GetActiveDesktop());
-  if (!browser)  // unit tests
+  if (!browser)  // Can be NULL in unittests.
     return;
   WebContents* web_contents =
       browser->tab_strip_model()->GetActiveWebContents();
diff --git a/chrome/browser/ui/fullscreen/fullscreen_controller.cc b/chrome/browser/ui/fullscreen/fullscreen_controller.cc
index df306d6..7c1621e 100644
--- a/chrome/browser/ui/fullscreen/fullscreen_controller.cc
+++ b/chrome/browser/ui/fullscreen/fullscreen_controller.cc
@@ -142,6 +142,9 @@
         if (state_prior_to_tab_fullscreen_ ==
             STATE_BROWSER_FULLSCREEN_WITH_CHROME) {
           EnterFullscreenModeInternal(BROWSER_WITH_CHROME);
+        } else {
+          // Clear the bubble URL, which forces the Mac UI to redraw.
+          UpdateFullscreenExitBubbleContent();
         }
 #endif
         // If currently there is a tab in "tab fullscreen" mode and fullscreen
@@ -191,6 +194,9 @@
 
 #if defined(OS_MACOSX)
 void FullscreenController::ToggleFullscreenWithChrome() {
+  // This method cannot be called if simplified fullscreen is enabled.
+  const CommandLine* command_line = CommandLine::ForCurrentProcess();
+  DCHECK(!command_line->HasSwitch(switches::kEnableSimplifiedFullscreen));
   ToggleFullscreenModeInternal(BROWSER_WITH_CHROME);
 }
 #endif
diff --git a/chrome/browser/ui/fullscreen/fullscreen_exit_bubble_type.cc b/chrome/browser/ui/fullscreen/fullscreen_exit_bubble_type.cc
index 6c06423..9cd835d 100644
--- a/chrome/browser/ui/fullscreen/fullscreen_exit_bubble_type.cc
+++ b/chrome/browser/ui/fullscreen/fullscreen_exit_bubble_type.cc
@@ -23,7 +23,7 @@
     const ExtensionSet* extensions = extension_service->extensions();
     DCHECK(extensions);
     const extensions::Extension* extension =
-        extensions->GetExtensionOrAppByURL(ExtensionURLInfo(url));
+        extensions->GetExtensionOrAppByURL(url);
     if (extension) {
       host = UTF8ToUTF16(extension->name());
     } else if (url.SchemeIs(extensions::kExtensionScheme)) {
@@ -130,4 +130,4 @@
   }
 }
 
-}  // namespace
+}  // namespace fullscreen_bubble
diff --git a/chrome/browser/ui/gtk/action_box_button_gtk.cc b/chrome/browser/ui/gtk/action_box_button_gtk.cc
deleted file mode 100644
index cd87e8a..0000000
--- a/chrome/browser/ui/gtk/action_box_button_gtk.cc
+++ /dev/null
@@ -1,164 +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/gtk/action_box_button_gtk.h"
-
-#include <gtk/gtk.h>
-
-#include "base/logging.h"
-#include "chrome/browser/extensions/extension_icon_image.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/gtk/custom_button.h"
-#include "chrome/browser/ui/gtk/view_id_util.h"
-#include "chrome/browser/ui/toolbar/action_box_menu_model.h"
-#include "chrome/browser/ui/view_ids.h"
-#include "chrome/common/extensions/api/extension_action/action_info.h"
-#include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/extension_constants.h"
-#include "chrome/common/extensions/manifest_handlers/icons_handler.h"
-#include "grit/generated_resources.h"
-#include "grit/theme_resources.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "ui/base/layout.h"
-#include "ui/gfx/gtk_util.h"
-#include "ui/gfx/image/image_skia.h"
-#include "ui/gfx/image/image_skia_rep.h"
-
-using extensions::ActionInfo;
-using extensions::Extension;
-using extensions::IconImage;
-
-namespace {
-
-// This class provides a GtkWidget that shows an Extension's page launcher icon.
-// We can't use GtkImage directly because loading the icon from the extension
-// must be done asynchronously. The lifetime of this object is tied to its
-// GtkWidget, and it will delete itself upon receiving a "destroy" signal from
-// the widget.
-class ExtensionIcon : public IconImage::Observer {
- public:
-  ExtensionIcon(Profile* profile, const Extension* extension);
-
-  GtkWidget* GetWidget();
-
- private:
-  virtual ~ExtensionIcon() {}
-
-  virtual void OnExtensionIconImageChanged(IconImage* image) OVERRIDE;
-  void UpdateIcon();
-
-  CHROMEGTK_CALLBACK_0(ExtensionIcon, void, OnDestroyed);
-
-  GtkWidget* image_;
-
-  scoped_ptr<IconImage> icon_;
-
-  DISALLOW_COPY_AND_ASSIGN(ExtensionIcon);
-};
-
-ExtensionIcon::ExtensionIcon(Profile* profile, const Extension* extension)
-    : image_(NULL) {
-  const ActionInfo* page_launcher_info =
-      ActionInfo::GetPageLauncherInfo(extension);
-  icon_.reset(new IconImage(profile,
-                            extension,
-                            page_launcher_info->default_icon,
-                            extension_misc::EXTENSION_ICON_ACTION,
-                            extensions::IconsInfo::GetDefaultAppIcon(),
-                            this));
-  UpdateIcon();
-}
-
-GtkWidget* ExtensionIcon::GetWidget() {
-  return image_;
-}
-
-void ExtensionIcon::OnExtensionIconImageChanged(IconImage* image)  {
-  DCHECK_EQ(image, icon_.get());
-  UpdateIcon();
-}
-
-void ExtensionIcon::UpdateIcon() {
-  const gfx::ImageSkiaRep& rep =
-      icon_->image_skia().GetRepresentation(ui::SCALE_FACTOR_NONE);
-  GdkPixbuf* pixbuf = gfx::GdkPixbufFromSkBitmap(rep.sk_bitmap());
-
-  if (!image_) {
-    image_ = gtk_image_new_from_pixbuf(pixbuf);
-    g_signal_connect(image_, "destroy", G_CALLBACK(OnDestroyedThunk), this);
-  } else {
-    gtk_image_set_from_pixbuf(GTK_IMAGE(image_), pixbuf);
-  }
-  g_object_unref(pixbuf);
-}
-
-void ExtensionIcon::OnDestroyed(GtkWidget* sender) {
-  DCHECK_EQ(sender, image_);
-  delete this;
-}
-
-}  // namespace
-
-ActionBoxButtonGtk::ActionBoxButtonGtk(Browser* browser)
-    : controller_(browser, this),
-      browser_(browser) {
-  button_.reset(new CustomDrawButton(
-      IDR_ACTION_BOX_BUTTON_NORMAL,
-      IDR_ACTION_BOX_BUTTON_PRESSED,
-      IDR_ACTION_BOX_BUTTON_HOVER,
-      0));  // TODO: disabled?
-  gtk_widget_set_tooltip_text(widget(),
-      l10n_util::GetStringUTF8(IDS_TOOLTIP_ACTION_BOX_BUTTON).c_str());
-
-  g_signal_connect(widget(), "button-press-event",
-                   G_CALLBACK(OnButtonPressThunk), this);
-
-  ViewIDUtil::SetID(widget(), VIEW_ID_ACTION_BOX_BUTTON);
-}
-
-ActionBoxButtonGtk::~ActionBoxButtonGtk() {
-}
-
-void ActionBoxButtonGtk:: StoppedShowing() {
-  button_->UnsetPaintOverride();
-}
-
-bool ActionBoxButtonGtk::AlwaysShowIconForCmd(int command_id) const {
-  return true;
-}
-
-GtkWidget* ActionBoxButtonGtk::GetImageForCommandId(int command_id) const {
-  int index = model_->GetIndexOfCommandId(command_id);
-  if (model_->IsItemExtension(index)) {
-    const Extension* extension = model_->GetExtensionAt(index);
-    return (new ExtensionIcon(browser_->profile(), extension))->GetWidget();
-  }
-
-  return GetDefaultImageForCommandId(command_id);
-}
-
-GtkWidget* ActionBoxButtonGtk::widget() {
-  return button_->widget();
-}
-
-void ActionBoxButtonGtk::ShowMenu(scoped_ptr<ActionBoxMenuModel> model) {
-  button_->SetPaintOverride(GTK_STATE_ACTIVE);
-  model_ = model.Pass();
-  menu_.reset(new MenuGtk(this, model_.get()));
-  menu_->PopupForWidget(
-      button_->widget(),
-      // The mouse button. This is 1 because currently it can only be generated
-      // from a mouse click, but if ShowMenu can be called in other situations
-      // (e.g. other mouse buttons, or without any click at all) then it will
-      // need to be that button or 0.
-      1,
-      gtk_get_current_event_time());
-}
-
-gboolean ActionBoxButtonGtk::OnButtonPress(GtkWidget* widget,
-                                           GdkEventButton* event) {
-  if (event->button == 1)
-    controller_.OnButtonClicked();
-  return FALSE;
-}
diff --git a/chrome/browser/ui/gtk/action_box_button_gtk.h b/chrome/browser/ui/gtk/action_box_button_gtk.h
deleted file mode 100644
index 423b0cb..0000000
--- a/chrome/browser/ui/gtk/action_box_button_gtk.h
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_GTK_ACTION_BOX_BUTTON_GTK_H_
-#define CHROME_BROWSER_UI_GTK_ACTION_BOX_BUTTON_GTK_H_
-
-#include "base/compiler_specific.h"
-#include "base/memory/scoped_ptr.h"
-#include "chrome/browser/ui/gtk/menu_gtk.h"
-#include "chrome/browser/ui/toolbar/action_box_button_controller.h"
-#include "ui/base/gtk/gtk_signal.h"
-
-class ActionBoxMenuModel;
-class Browser;
-class CustomDrawButton;
-
-typedef struct _GtkWidget GtkWidget;
-
-// This class displays the action box button with an associated menu. This is
-// where extension actions and the bookmark star live.
-class ActionBoxButtonGtk : public MenuGtk::Delegate,
-                           public ActionBoxButtonController::Delegate {
- public:
-  explicit ActionBoxButtonGtk(Browser* browser);
-  virtual ~ActionBoxButtonGtk();
-
-  // MenuGtk::Delegate implementation.
-  virtual void StoppedShowing() OVERRIDE;
-  virtual bool AlwaysShowIconForCmd(int command_id) const OVERRIDE;
-  virtual GtkWidget* GetImageForCommandId(int command_id) const OVERRIDE;
-
-  GtkWidget* widget();
-
-  ActionBoxButtonController* action_box_button_controller() {
-    return &controller_;
-  }
-
- private:
-  // ActionBoxButtonController::Delegate implementation.
-  virtual void ShowMenu(scoped_ptr<ActionBoxMenuModel> model) OVERRIDE;
-
-  // Show the action box menu.
-  CHROMEGTK_CALLBACK_1(ActionBoxButtonGtk, gboolean, OnButtonPress,
-                       GdkEventButton*);
-
-  ActionBoxButtonController controller_;
-
-  scoped_ptr<CustomDrawButton> button_;
-
-  // The browser to which we will send commands.
-  Browser* browser_;
-
-  // The model and menu displayed when the button is clicked. The menu is
-  // recreated every time it is displayed.
-  scoped_ptr<ActionBoxMenuModel> model_;
-  scoped_ptr<MenuGtk> menu_;
-
-  DISALLOW_COPY_AND_ASSIGN(ActionBoxButtonGtk);
-};
-
-#endif  // CHROME_BROWSER_UI_GTK_ACTION_BOX_BUTTON_GTK_H_
diff --git a/chrome/browser/ui/gtk/bookmarks/bookmark_bubble_gtk.cc b/chrome/browser/ui/gtk/bookmarks/bookmark_bubble_gtk.cc
index f854da6..c74edca 100644
--- a/chrome/browser/ui/gtk/bookmarks/bookmark_bubble_gtk.cc
+++ b/chrome/browser/ui/gtk/bookmarks/bookmark_bubble_gtk.cc
@@ -8,6 +8,7 @@
 
 #include "base/basictypes.h"
 #include "base/bind.h"
+#include "base/command_line.h"
 #include "base/i18n/rtl.h"
 #include "base/logging.h"
 #include "base/message_loop/message_loop.h"
@@ -18,32 +19,63 @@
 #include "chrome/browser/bookmarks/bookmark_utils.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/themes/theme_properties.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_finder.h"
 #include "chrome/browser/ui/browser_list.h"
+#include "chrome/browser/ui/chrome_pages.h"
 #include "chrome/browser/ui/gtk/gtk_theme_service.h"
 #include "chrome/browser/ui/gtk/gtk_util.h"
+#include "chrome/browser/ui/sync/sync_promo_ui.h"
+#include "chrome/common/chrome_switches.h"
 #include "content/public/browser/notification_source.h"
 #include "content/public/browser/user_metrics.h"
 #include "grit/generated_resources.h"
 #include "ui/base/gtk/gtk_hig_constants.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "ui/gfx/canvas_paint_gtk.h"
 
 using content::UserMetricsAction;
 
 namespace {
 
-// We basically have a singleton, since a bubble is sort of app-modal.  This
-// keeps track of the currently open bubble, or NULL if none is open.
-BookmarkBubbleGtk* g_bubble = NULL;
-
 enum {
   COLUMN_NAME,
   COLUMN_IS_SEPARATOR,
   COLUMN_COUNT
 };
 
+// Thickness of the bubble's border.
+const int kBubbleBorderThickness = 1;
+
+// Color of the bubble's border.
+const SkColor kBubbleBorderColor = SkColorSetRGB(0x63, 0x63, 0x63);
+
+// Background color of the sync promo.
+const GdkColor kPromoBackgroundColor = GDK_COLOR_RGB(0xf5, 0xf5, 0xf5);
+
+// Color of the border of the sync promo.
+const SkColor kPromoBorderColor = SkColorSetRGB(0xe5, 0xe5, 0xe5);
+
+// Color of the text in the sync promo.
+const GdkColor kPromoTextColor = GDK_COLOR_RGB(0x66, 0x66, 0x66);
+
+// Vertical padding inside the sync promo.
+const int kPromoVerticalPadding = 15;
+
+// Pango markup for the "Sign in" link in the sync promo.
+const char kPromoLinkMarkup[] =
+    "<a href='signin'><span underline='none'>%s</span></a>";
+
+// Style to make the sync promo link blue.
+const char kPromoLinkStyle[] =
+    "style \"sign-in-link\" {\n"
+    "  GtkWidget::link-color=\"blue\"\n"
+    "}\n"
+    "widget \"*sign-in-link\" style \"sign-in-link\"\n";
+
 gboolean IsSeparator(GtkTreeModel* model, GtkTreeIter* iter, gpointer data) {
   gboolean is_separator;
   gtk_tree_model_get(model, iter, COLUMN_IS_SEPARATOR, &is_separator, -1);
@@ -52,6 +84,8 @@
 
 }  // namespace
 
+BookmarkBubbleGtk* BookmarkBubbleGtk::bookmark_bubble_ = NULL;
+
 // static
 void BookmarkBubbleGtk::Show(GtkWidget* anchor,
                              Profile* profile,
@@ -59,9 +93,12 @@
                              bool newly_bookmarked) {
   // Sometimes Ctrl+D may get pressed more than once on top level window
   // before the bookmark bubble window is shown and takes the keyboad focus.
-  if (g_bubble)
+  if (bookmark_bubble_)
     return;
-  g_bubble = new BookmarkBubbleGtk(anchor, profile, url, newly_bookmarked);
+  bookmark_bubble_ = new BookmarkBubbleGtk(anchor,
+                                           profile,
+                                           url,
+                                           newly_bookmarked);
 }
 
 void BookmarkBubbleGtk::BubbleClosing(BubbleGtk* bubble,
@@ -88,6 +125,8 @@
       gtk_widget_modify_fg(*it, GTK_STATE_NORMAL, &ui::kGdkBlack);
     }
   }
+
+  UpdatePromoColors();
 }
 
 BookmarkBubbleGtk::BookmarkBubbleGtk(GtkWidget* anchor,
@@ -99,6 +138,8 @@
       model_(BookmarkModelFactory::GetForProfile(profile)),
       theme_service_(GtkThemeService::GetFrom(profile_)),
       anchor_(anchor),
+      promo_(NULL),
+      promo_label_(NULL),
       name_entry_(NULL),
       folder_combo_(NULL),
       bubble_(NULL),
@@ -117,13 +158,20 @@
   GtkWidget* close_button = gtk_button_new_with_label(
       l10n_util::GetStringUTF8(IDS_DONE).c_str());
 
+  GtkWidget* bubble_container = gtk_vbox_new(FALSE, 0);
+
+  // Prevent the content of the bubble to be drawn on the border.
+  gtk_container_set_border_width(GTK_CONTAINER(bubble_container),
+                                 kBubbleBorderThickness);
+
   // Our content is arranged in 3 rows.  |top| contains a left justified
   // message, and a right justified remove link button.  |table| is the middle
   // portion with the name entry and the folder combo.  |bottom| is the final
   // row with a spacer, and the edit... and close buttons on the right.
   GtkWidget* content = gtk_vbox_new(FALSE, 5);
-  gtk_container_set_border_width(GTK_CONTAINER(content),
-                                 ui::kContentAreaBorder);
+  gtk_container_set_border_width(
+      GTK_CONTAINER(content),
+      ui::kContentAreaBorder - kBubbleBorderThickness);
   GtkWidget* top = gtk_hbox_new(FALSE, 0);
 
   gtk_misc_set_alignment(GTK_MISC(label), 0, 1);
@@ -164,9 +212,57 @@
   // We want the focus to start on the entry, not on the remove button.
   gtk_container_set_focus_child(GTK_CONTAINER(content), table);
 
+  gtk_box_pack_start(GTK_BOX(bubble_container), content, TRUE, TRUE, 0);
+
+  const CommandLine* command_line = CommandLine::ForCurrentProcess();
+  if (command_line->HasSwitch(switches::kEnableBookmarkSyncPromo) &&
+      SyncPromoUI::ShouldShowSyncPromo(profile_)) {
+    std::string link_text =
+        l10n_util::GetStringUTF8(IDS_BOOKMARK_SYNC_PROMO_LINK);
+    char* link_markup = g_markup_printf_escaped(kPromoLinkMarkup,
+                                                link_text.c_str());
+    string16 link_markup_utf16;
+    base::UTF8ToUTF16(link_markup, strlen(link_markup), &link_markup_utf16);
+    g_free(link_markup);
+
+    std::string promo_markup = l10n_util::GetStringFUTF8(
+        IDS_BOOKMARK_SYNC_PROMO_MESSAGE,
+        link_markup_utf16);
+
+    promo_ = gtk_event_box_new();
+    gtk_widget_set_app_paintable(promo_, TRUE);
+
+    promo_label_ = gtk_label_new(NULL);
+    gtk_label_set_markup(GTK_LABEL(promo_label_), promo_markup.c_str());
+    gtk_misc_set_alignment(GTK_MISC(promo_label_), 0.0, 0.0);
+    gtk_misc_set_padding(GTK_MISC(promo_label_),
+                         ui::kContentAreaBorder,
+                         kPromoVerticalPadding);
+
+    // Custom link color.
+    gtk_rc_parse_string(kPromoLinkStyle);
+
+    UpdatePromoColors();
+
+    gtk_container_add(GTK_CONTAINER(promo_), promo_label_);
+    gtk_box_pack_start(GTK_BOX(bubble_container), promo_, TRUE, TRUE, 0);
+    g_signal_connect(promo_,
+                     "realize",
+                     G_CALLBACK(&OnSyncPromoRealizeThunk),
+                     this);
+    g_signal_connect(promo_,
+                     "expose-event",
+                     G_CALLBACK(&OnSyncPromoExposeThunk),
+                     this);
+    g_signal_connect(promo_label_,
+                     "activate-link",
+                     G_CALLBACK(&OnSignInClickedThunk),
+                     this);
+  }
+
   bubble_ = BubbleGtk::Show(anchor_,
                             NULL,
-                            content,
+                            bubble_container,
                             BubbleGtk::ANCHOR_TOP_RIGHT,
                             BubbleGtk::MATCH_SYSTEM_THEME |
                                 BubbleGtk::POPUP_WINDOW |
@@ -197,8 +293,8 @@
 }
 
 BookmarkBubbleGtk::~BookmarkBubbleGtk() {
-  DCHECK(g_bubble);
-  g_bubble = NULL;
+  DCHECK(bookmark_bubble_);
+  bookmark_bubble_ = NULL;
 
   if (apply_edits_) {
     ApplyEdits();
@@ -251,6 +347,70 @@
   bubble_->Close();
 }
 
+gboolean BookmarkBubbleGtk::OnSignInClicked(GtkWidget* widget, gchar* uri) {
+  GtkWindow* window = GTK_WINDOW(gtk_widget_get_toplevel(anchor_));
+  Browser* browser = chrome::FindBrowserWithWindow(window);
+  chrome::ShowBrowserSignin(browser, SyncPromoUI::SOURCE_BOOKMARK_BUBBLE);
+  bubble_->Close();
+  return TRUE;
+}
+
+void BookmarkBubbleGtk::OnSyncPromoRealize(GtkWidget* widget) {
+  int width = gtk_util::GetWidgetSize(widget).width();
+  gtk_util::SetLabelWidth(promo_label_, width);
+}
+
+gboolean BookmarkBubbleGtk::OnSyncPromoExpose(GtkWidget* widget,
+                                              GdkEventExpose* event) {
+  GtkAllocation allocation;
+  gtk_widget_get_allocation(widget, &allocation);
+
+  gfx::CanvasSkiaPaint canvas(event);
+
+  // Draw a border on top of the promo.
+  canvas.DrawLine(gfx::Point(0, 0),
+                  gfx::Point(allocation.width + 1, 0),
+                  kPromoBorderColor);
+
+  // Redraw the rounded corners of the bubble that are hidden by the
+  // background of the promo.
+  SkPaint points_paint;
+  points_paint.setColor(kBubbleBorderColor);
+  points_paint.setStrokeWidth(SkIntToScalar(1));
+  canvas.DrawPoint(gfx::Point(0, allocation.height - 1), points_paint);
+  canvas.DrawPoint(gfx::Point(allocation.width - 1, allocation.height - 1),
+                   points_paint);
+
+  return FALSE; // Propagate expose to children.
+}
+
+void BookmarkBubbleGtk::UpdatePromoColors() {
+  if (!promo_)
+    return;
+
+  GdkColor promo_background_color;
+
+  if (!theme_service_->UsingNativeTheme()) {
+    promo_background_color = kPromoBackgroundColor;
+    gtk_widget_set_name(promo_label_, "sign-in-link");
+    gtk_util::SetLabelColor(promo_label_, &kPromoTextColor);
+  } else {
+    promo_background_color = theme_service_->GetGdkColor(
+        ThemeProperties::COLOR_TOOLBAR);
+    gtk_widget_set_name(promo_label_, "sign-in-link-theme-color");
+  }
+
+  gtk_widget_modify_bg(promo_, GTK_STATE_NORMAL, &promo_background_color);
+
+  // No visible highlight color when the mouse is over the link.
+  gtk_widget_modify_base(promo_label_,
+                         GTK_STATE_ACTIVE,
+                         &promo_background_color);
+  gtk_widget_modify_base(promo_label_,
+                         GTK_STATE_PRELIGHT,
+                         &promo_background_color);
+}
+
 void BookmarkBubbleGtk::ApplyEdits() {
   // Set this to make sure we don't attempt to apply edits again.
   apply_edits_ = false;
diff --git a/chrome/browser/ui/gtk/bookmarks/bookmark_bubble_gtk.h b/chrome/browser/ui/gtk/bookmarks/bookmark_bubble_gtk.h
index 22e7f4a..6452f87 100644
--- a/chrome/browser/ui/gtk/bookmarks/bookmark_bubble_gtk.h
+++ b/chrome/browser/ui/gtk/bookmarks/bookmark_bubble_gtk.h
@@ -17,6 +17,7 @@
 
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
+#include "base/gtest_prod_util.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/ui/gtk/bubble/bubble_gtk.h"
@@ -50,6 +51,11 @@
                        const content::NotificationDetails& details) OVERRIDE;
 
  private:
+  friend class BookmarkBubbleGtkBrowserTest;
+  FRIEND_TEST_ALL_PREFIXES(BookmarkBubbleGtkBrowserTest, SyncPromoSignedIn);
+  FRIEND_TEST_ALL_PREFIXES(BookmarkBubbleGtkBrowserTest, SyncPromoNotSignedIn);
+  FRIEND_TEST_ALL_PREFIXES(BookmarkBubbleGtkBrowserTest, SyncPromoLink);
+
   BookmarkBubbleGtk(GtkWidget* anchor,
                     Profile* profile,
                     const GURL& url,
@@ -63,6 +69,18 @@
   CHROMEGTK_CALLBACK_0(BookmarkBubbleGtk, void, OnEditClicked);
   CHROMEGTK_CALLBACK_0(BookmarkBubbleGtk, void, OnCloseClicked);
   CHROMEGTK_CALLBACK_0(BookmarkBubbleGtk, void, OnRemoveClicked);
+  CHROMEGTK_CALLBACK_1(BookmarkBubbleGtk,
+                       gboolean,
+                       OnSignInClicked,
+                       gchar*);
+  CHROMEGTK_CALLBACK_0(BookmarkBubbleGtk, void, OnSyncPromoRealize);
+  CHROMEGTK_CALLBACK_1(BookmarkBubbleGtk,
+                       gboolean,
+                       OnSyncPromoExpose,
+                       GdkEventExpose*);
+
+  // Sets the colors used in the sync promo according to the current theme.
+  void UpdatePromoColors();
 
   // Update the bookmark with any edits that have been made.
   void ApplyEdits();
@@ -75,6 +93,10 @@
 
   void InitFolderComboModel();
 
+  // We basically have a singleton, since a bubble is sort of app-modal.  This
+  // keeps track of the currently open bubble, or NULL if none is open.
+  static BookmarkBubbleGtk* bookmark_bubble_;
+
   // The URL of the bookmark.
   GURL url_;
 
@@ -93,6 +115,12 @@
   // The button that removes the bookmark.
   GtkWidget* remove_button_;
 
+  // The bookmark sync promo, if shown.
+  GtkWidget* promo_;
+
+  // The label in the bookmark sync promo, if shown.
+  GtkWidget* promo_label_;
+
   // The various labels in the interface. We keep track of them for theme
   // changes.
   std::vector<GtkWidget*> labels_;
diff --git a/chrome/browser/ui/gtk/bookmarks/bookmark_bubble_gtk_browsertest.cc b/chrome/browser/ui/gtk/bookmarks/bookmark_bubble_gtk_browsertest.cc
new file mode 100644
index 0000000..f1fb093
--- /dev/null
+++ b/chrome/browser/ui/gtk/bookmarks/bookmark_bubble_gtk_browsertest.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/ui/gtk/bookmarks/bookmark_bubble_gtk.h"
+
+#include "base/command_line.h"
+#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
+#include "chrome/browser/bookmarks/bookmark_model_factory.h"
+#include "chrome/browser/bookmarks/bookmark_utils.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/browser_window.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.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 "content/public/browser/web_contents.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+const char kTestBookmarkURL[] = "http://www.google.com";
+} // namespace
+
+class BookmarkBubbleGtkBrowserTest : public InProcessBrowserTest {
+ public:
+  BookmarkBubbleGtkBrowserTest() {}
+
+  // content::BrowserTestBase:
+  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
+    command_line->AppendSwitch(switches::kEnableBookmarkSyncPromo);
+  }
+
+  virtual void SetUpOnMainThread() OVERRIDE {
+    bookmark_utils::AddIfNotBookmarked(
+        BookmarkModelFactory::GetForProfile(browser()->profile()),
+        GURL(kTestBookmarkURL),
+        string16());
+  }
+
+ protected:
+  // Creates a bookmark bubble.
+  void CreateBookmarkBubble() {
+    BookmarkBubbleGtk::Show(GTK_WIDGET(browser()->window()->GetNativeWindow()),
+                            browser()->profile(),
+                            GURL(kTestBookmarkURL),
+                            true);
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(BookmarkBubbleGtkBrowserTest);
+};
+
+// Verifies that the sync promo is not displayed for a signed in user.
+IN_PROC_BROWSER_TEST_F(BookmarkBubbleGtkBrowserTest, SyncPromoSignedIn) {
+  SigninManager* signin = SigninManagerFactory::GetForProfile(
+      browser()->profile());
+  signin->SetAuthenticatedUsername("fake_username");
+
+  CreateBookmarkBubble();
+  EXPECT_FALSE(BookmarkBubbleGtk::bookmark_bubble_->promo_);
+}
+
+// Verifies that the sync promo is displayed for a user that is not signed in.
+IN_PROC_BROWSER_TEST_F(BookmarkBubbleGtkBrowserTest, SyncPromoNotSignedIn) {
+  CreateBookmarkBubble();
+  EXPECT_TRUE(BookmarkBubbleGtk::bookmark_bubble_->promo_);
+}
+
+// Verifies that a new tab is opened when the "Sign in" link is clicked.
+IN_PROC_BROWSER_TEST_F(BookmarkBubbleGtkBrowserTest, SyncPromoLink) {
+  GURL initial_url =
+      browser()->tab_strip_model()->GetActiveWebContents()->GetVisibleURL();
+  CreateBookmarkBubble();
+
+  // Simulate clicking the "Sign in" link.
+  BookmarkBubbleGtk::bookmark_bubble_->OnSignInClicked(NULL, NULL);
+
+  EXPECT_NE(
+      initial_url,
+      browser()->tab_strip_model()->GetActiveWebContents()->GetVisibleURL());
+}
+
diff --git a/chrome/browser/ui/gtk/extensions/media_galleries_dialog_gtk_unittest.cc b/chrome/browser/ui/gtk/extensions/media_galleries_dialog_gtk_unittest.cc
index 5490cec..089cf89 100644
--- a/chrome/browser/ui/gtk/extensions/media_galleries_dialog_gtk_unittest.cc
+++ b/chrome/browser/ui/gtk/extensions/media_galleries_dialog_gtk_unittest.cc
@@ -6,7 +6,6 @@
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/media_galleries/media_galleries_dialog_controller_mock.h"
 #include "chrome/browser/storage_monitor/storage_info.h"
-#include "chrome/browser/storage_monitor/test_storage_monitor.h"
 #include "chrome/browser/ui/gtk/extensions/media_galleries_dialog_gtk.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -33,8 +32,6 @@
 }  // namespace
 
 class MediaGalleriesDialogTest : public testing::Test {
- private:
-  test::TestStorageMonitor test_storage_monitor_;
 };
 
 // Tests that checkboxes are initialized according to the contents of
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 e96e322..4154834 100644
--- a/chrome/browser/ui/gtk/extensions/native_app_window_gtk.cc
+++ b/chrome/browser/ui/gtk/extensions/native_app_window_gtk.cc
@@ -4,6 +4,10 @@
 
 #include "chrome/browser/ui/gtk/extensions/native_app_window_gtk.h"
 
+#include <gdk/gdkx.h>
+#include <vector>
+
+#include "base/message_loop/message_pump_gtk.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/gtk/extensions/extension_keybinding_registry_gtk.h"
@@ -28,6 +32,12 @@
 // gtk_window_get_position() after the last GTK configure-event signal.
 const int kDebounceTimeoutMilliseconds = 100;
 
+const char* kAtomsToCache[] = {
+  "_NET_WM_STATE",
+  "_NET_WM_STATE_HIDDEN",
+  NULL
+};
+
 } // namespace
 
 NativeAppWindowGtk::NativeAppWindowGtk(ShellWindow* shell_window,
@@ -38,7 +48,9 @@
       is_active_(false),
       content_thinks_its_fullscreen_(false),
       frameless_(params.frame == ShellWindow::FRAME_NONE),
-      frame_cursor_(NULL) {
+      frame_cursor_(NULL),
+      atom_cache_(base::MessagePumpGtk::GetDefaultXDisplay(), kAtomsToCache),
+      is_x_event_listened_(false) {
   window_ = GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL));
 
   gfx::NativeView native_view =
@@ -128,6 +140,25 @@
                      G_CALLBACK(OnMouseMoveEventThunk), this);
   }
 
+  // If _NET_WM_STATE_HIDDEN is in _NET_SUPPORTED, listen for XEvent to work
+  // around GTK+ not reporting minimization state changes. See comment in the
+  // |OnXEvent|.
+  std::vector< ::Atom> supported_atoms;
+  if (ui::GetAtomArrayProperty(ui::GetX11RootWindow(),
+                               "_NET_SUPPORTED",
+                               &supported_atoms)) {
+    if (std::find(supported_atoms.begin(),
+                  supported_atoms.end(),
+                  atom_cache_.GetAtom("_NET_WM_STATE_HIDDEN")) !=
+        supported_atoms.end()) {
+      GdkWindow* window = gtk_widget_get_window(GTK_WIDGET(window_));
+      gdk_window_add_filter(window,
+                            &NativeAppWindowGtk::OnXEventThunk,
+                            this);
+      is_x_event_listened_ = true;
+    }
+  }
+
   // Add the keybinding registry.
   extension_keybinding_registry_.reset(new ExtensionKeybindingRegistryGtk(
       shell_window_->profile(),
@@ -140,6 +171,11 @@
 
 NativeAppWindowGtk::~NativeAppWindowGtk() {
   ui::ActiveWindowWatcherX::RemoveObserver(this);
+  if (is_x_event_listened_) {
+    gdk_window_remove_filter(NULL,
+                             &NativeAppWindowGtk::OnXEventThunk,
+                             this);
+  }
 }
 
 bool NativeAppWindowGtk::IsActive() const {
@@ -224,6 +260,10 @@
 }
 
 void NativeAppWindowGtk::Maximize() {
+  // Represent the window first in order to keep the maximization behavior
+  // consistency with Windows platform. Otherwise the window will be hidden if
+  // it has been minimized.
+  gtk_window_present(window_);
   gtk_window_maximize(window_);
 }
 
@@ -236,6 +276,12 @@
     gtk_window_unmaximize(window_);
   else if (IsMinimized())
     gtk_window_deiconify(window_);
+
+  // Represent the window to keep restoration behavior consistency with Windows
+  // platform.
+  // TODO(zhchbin): verify whether we need this until http://crbug.com/261013 is
+  // fixed.
+  gtk_window_present(window_);
 }
 
 void NativeAppWindowGtk::SetBounds(const gfx::Rect& bounds) {
@@ -257,6 +303,33 @@
   }
 }
 
+GdkFilterReturn NativeAppWindowGtk::OnXEvent(GdkXEvent* gdk_x_event,
+                                             GdkEvent* gdk_event) {
+  // Work around GTK+ not reporting minimization state changes. Listen
+  // for _NET_WM_STATE property changes and use _NET_WM_STATE_HIDDEN's
+  // presence to set or clear the iconified bit if _NET_WM_STATE_HIDDEN
+  // is supported. http://crbug.com/162794.
+  XEvent* x_event = static_cast<XEvent*>(gdk_x_event);
+  std::vector< ::Atom> atom_list;
+
+  if (x_event->type == PropertyNotify &&
+      x_event->xproperty.atom == atom_cache_.GetAtom("_NET_WM_STATE") &&
+      ui::GetAtomArrayProperty(GDK_WINDOW_XWINDOW(GTK_WIDGET(window_)->window),
+                               "_NET_WM_STATE",
+                               &atom_list)) {
+    std::vector< ::Atom>::iterator it =
+        std::find(atom_list.begin(),
+                  atom_list.end(),
+                  atom_cache_.GetAtom("_NET_WM_STATE_HIDDEN"));
+    state_ = (it != atom_list.end()) ? GDK_WINDOW_STATE_ICONIFIED :
+        static_cast<GdkWindowState>(state_ & ~GDK_WINDOW_STATE_ICONIFIED);
+
+    shell_window_->OnNativeWindowChanged();
+  }
+
+  return GDK_FILTER_CONTINUE;
+}
+
 void NativeAppWindowGtk::FlashFrame(bool flash) {
   gtk_window_set_urgency_hint(window_, flash);
 }
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 2b71243..ce5ece9 100644
--- a/chrome/browser/ui/gtk/extensions/native_app_window_gtk.h
+++ b/chrome/browser/ui/gtk/extensions/native_app_window_gtk.h
@@ -15,6 +15,7 @@
 #include "third_party/skia/include/core/SkRegion.h"
 #include "ui/base/gtk/gtk_signal.h"
 #include "ui/base/x/active_window_watcher_x_observer.h"
+#include "ui/base/x/x11_atom_cache.h"
 #include "ui/gfx/rect.h"
 
 class ExtensionKeybindingRegistryGtk;
@@ -102,6 +103,9 @@
                        GdkEventMotion*);
   CHROMEGTK_CALLBACK_1(NativeAppWindowGtk, gboolean, OnButtonPress,
                        GdkEventButton*);
+  // Callback for PropertyChange XEvents.
+  CHROMEG_CALLBACK_1(NativeAppWindowGtk, GdkFilterReturn,
+                     OnXEvent, GdkXEvent*, GdkEvent*);
 
   void OnConfigureDebounced();
 
@@ -155,6 +159,11 @@
   // updating its dimensions.
   ObserverList<web_modal::WebContentsModalDialogHostObserver> observer_list_;
 
+  ui::X11AtomCache atom_cache_;
+
+  // True if we listen for the XEvent.
+  bool is_x_event_listened_;
+
   DISALLOW_COPY_AND_ASSIGN(NativeAppWindowGtk);
 };
 
diff --git a/chrome/browser/ui/gtk/infobars/extension_infobar_gtk.cc b/chrome/browser/ui/gtk/infobars/extension_infobar_gtk.cc
index bb87abb..c12d975 100644
--- a/chrome/browser/ui/gtk/infobars/extension_infobar_gtk.cc
+++ b/chrome/browser/ui/gtk/infobars/extension_infobar_gtk.cc
@@ -47,15 +47,15 @@
       icon_(NULL),
       alignment_(NULL),
       weak_ptr_factory_(this) {
-  delegate->set_observer(this);
+  GetDelegate()->set_observer(this);
 
-  int height = delegate->height();
+  int height = GetDelegate()->height();
   SetBarTargetHeight((height > 0) ? (height + kSeparatorLineHeight) : 0);
 }
 
 ExtensionInfoBarGtk::~ExtensionInfoBarGtk() {
-  if (delegate_)
-    delegate_->set_observer(NULL);
+  if (GetDelegate())
+    GetDelegate()->set_observer(NULL);
 }
 
 void ExtensionInfoBarGtk::PlatformSpecificHide(bool animate) {
@@ -75,42 +75,6 @@
   *r = *g = *b = 218.0 / 255.0;
 }
 
-void ExtensionInfoBarGtk::OnImageLoaded(const gfx::Image& image) {
-
-  DCHECK(icon_);
-  // TODO(erg): IDR_EXTENSIONS_SECTION should have an IDR_INFOBAR_EXTENSIONS
-  // icon of the correct size with real subpixel shading and such.
-  const gfx::ImageSkia* icon = NULL;
-  ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
-  if (image.IsEmpty())
-    icon = rb.GetImageSkiaNamed(IDR_EXTENSIONS_SECTION);
-  else
-    icon = image.ToImageSkia();
-
-  SkBitmap bitmap;
-  if (button_) {
-    gfx::ImageSkia* drop_image = rb.GetImageSkiaNamed(IDR_APP_DROPARROW);
-
-    int image_size = extension_misc::EXTENSION_ICON_BITTY;
-    // The margin between the extension icon and the drop-down arrow bitmap.
-    static const int kDropArrowLeftMargin = 3;
-    scoped_ptr<gfx::Canvas> canvas(new gfx::Canvas(
-        gfx::Size(image_size + kDropArrowLeftMargin + drop_image->width(),
-                  image_size), ui::SCALE_FACTOR_100P, false));
-    canvas->DrawImageInt(*icon, 0, 0, icon->width(), icon->height(), 0, 0,
-                         image_size, image_size, false);
-    canvas->DrawImageInt(*drop_image, image_size + kDropArrowLeftMargin,
-                         image_size / 2);
-    bitmap = canvas->ExtractImageRep().sk_bitmap();
-  } else {
-    bitmap = *icon->bitmap();
-  }
-
-  GdkPixbuf* pixbuf = gfx::GdkPixbufFromSkBitmap(bitmap);
-  gtk_image_set_from_pixbuf(GTK_IMAGE(icon_), pixbuf);
-  g_object_unref(pixbuf);
-}
-
 void ExtensionInfoBarGtk::InitWidgets() {
   InfoBarGtk::InitWidgets();
 
@@ -124,7 +88,7 @@
   icon_ = gtk_image_new();
   gtk_misc_set_alignment(GTK_MISC(icon_), 0.5, 0.5);
 
-  extensions::ExtensionHost* extension_host = delegate_->extension_host();
+  extensions::ExtensionHost* extension_host = GetDelegate()->extension_host();
   const extensions::Extension* extension = extension_host->extension();
 
   if (extension->ShowConfigureContextMenus()) {
@@ -147,7 +111,7 @@
           ExtensionIconSet::MATCH_EXACTLY);
   // Load image asynchronously, calling back OnImageLoaded.
   extensions::ImageLoader* loader =
-      extensions::ImageLoader::Get(delegate_->extension_host()->profile());
+      extensions::ImageLoader::Get(extension_host->profile());
   loader->LoadImageAsync(extension, icon_resource,
                          gfx::Size(extension_misc::EXTENSION_ICON_BITTY,
                                    extension_misc::EXTENSION_ICON_BITTY),
@@ -186,6 +150,46 @@
   delegate_ = NULL;
 }
 
+void ExtensionInfoBarGtk::OnImageLoaded(const gfx::Image& image) {
+
+  DCHECK(icon_);
+  // TODO(erg): IDR_EXTENSIONS_SECTION should have an IDR_INFOBAR_EXTENSIONS
+  // icon of the correct size with real subpixel shading and such.
+  const gfx::ImageSkia* icon = NULL;
+  ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
+  if (image.IsEmpty())
+    icon = rb.GetImageSkiaNamed(IDR_EXTENSIONS_SECTION);
+  else
+    icon = image.ToImageSkia();
+
+  SkBitmap bitmap;
+  if (button_) {
+    gfx::ImageSkia* drop_image = rb.GetImageSkiaNamed(IDR_APP_DROPARROW);
+
+    int image_size = extension_misc::EXTENSION_ICON_BITTY;
+    // The margin between the extension icon and the drop-down arrow bitmap.
+    static const int kDropArrowLeftMargin = 3;
+    scoped_ptr<gfx::Canvas> canvas(new gfx::Canvas(
+        gfx::Size(image_size + kDropArrowLeftMargin + drop_image->width(),
+                  image_size), ui::SCALE_FACTOR_100P, false));
+    canvas->DrawImageInt(*icon, 0, 0, icon->width(), icon->height(), 0, 0,
+                         image_size, image_size, false);
+    canvas->DrawImageInt(*drop_image, image_size + kDropArrowLeftMargin,
+                         image_size / 2);
+    bitmap = canvas->ExtractImageRep().sk_bitmap();
+  } else {
+    bitmap = *icon->bitmap();
+  }
+
+  GdkPixbuf* pixbuf = gfx::GdkPixbufFromSkBitmap(bitmap);
+  gtk_image_set_from_pixbuf(GTK_IMAGE(icon_), pixbuf);
+  g_object_unref(pixbuf);
+}
+
+ExtensionInfoBarDelegate* ExtensionInfoBarGtk::GetDelegate() {
+  return delegate_ ? delegate_->AsExtensionInfoBarDelegate() : NULL;
+}
+
 Browser* ExtensionInfoBarGtk::GetBrowser() {
   DCHECK(icon_);
   // Get the Browser object this infobar is attached to.
@@ -196,7 +200,7 @@
 }
 
 ExtensionContextMenuModel* ExtensionInfoBarGtk::BuildMenuModel() {
-  const extensions::Extension* extension = delegate_->extension();
+  const extensions::Extension* extension = GetDelegate()->extension();
   if (!extension->ShowConfigureContextMenus())
     return NULL;
 
@@ -211,7 +215,7 @@
                                          GtkAllocation* allocation) {
   gfx::Size new_size(allocation->width, allocation->height);
 
-  delegate_->extension_host()->view()->render_view_host()->GetView()->
+  GetDelegate()->extension_host()->view()->render_view_host()->GetView()->
       SetSize(new_size);
 }
 
diff --git a/chrome/browser/ui/gtk/infobars/extension_infobar_gtk.h b/chrome/browser/ui/gtk/infobars/extension_infobar_gtk.h
index 3cd73d8..71c9c2a 100644
--- a/chrome/browser/ui/gtk/infobars/extension_infobar_gtk.h
+++ b/chrome/browser/ui/gtk/infobars/extension_infobar_gtk.h
@@ -42,6 +42,8 @@
 
   void OnImageLoaded(const gfx::Image& image);
 
+  ExtensionInfoBarDelegate* GetDelegate();
+
   // Looks at the window the infobar is in and gets the browser. Can return
   // NULL if we aren't attached.
   Browser* GetBrowser();
@@ -59,7 +61,10 @@
   CHROMEGTK_CALLBACK_1(ExtensionInfoBarGtk, gboolean, OnExpose,
                        GdkEventExpose*);
 
-  ExtensionInfoBarDelegate* delegate_;
+  // TODO(pkasting): This shadows InfoBarView::delegate_.  Get rid of this once
+  // InfoBars own their delegates (and thus we don't need the DelegateObserver
+  // functionality).  For now, almost everyone should use GetDelegate() instead.
+  InfoBarDelegate* delegate_;
 
   ExtensionViewGtk* view_;
 
diff --git a/chrome/browser/ui/gtk/infobars/infobar_gtk.cc b/chrome/browser/ui/gtk/infobars/infobar_gtk.cc
index 49907ea..ab2417b 100644
--- a/chrome/browser/ui/gtk/infobars/infobar_gtk.cc
+++ b/chrome/browser/ui/gtk/infobars/infobar_gtk.cc
@@ -7,7 +7,6 @@
 #include "base/debug/trace_event.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/infobars/infobar_service.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/themes/theme_properties.h"
 #include "chrome/browser/ui/gtk/browser_window_gtk.h"
diff --git a/chrome/browser/ui/gtk/infobars/translate_infobar_base_gtk.cc b/chrome/browser/ui/gtk/infobars/translate_infobar_base_gtk.cc
index a31fc6f..1d06498 100644
--- a/chrome/browser/ui/gtk/infobars/translate_infobar_base_gtk.cc
+++ b/chrome/browser/ui/gtk/infobars/translate_infobar_base_gtk.cc
@@ -52,7 +52,7 @@
       background_color_animation_->Hide();
     }
   } else {
-    background_error_percent_ = delegate->IsError() ? 1 : 0;
+    background_error_percent_ = delegate->is_error() ? 1 : 0;
   }
 }
 
@@ -127,7 +127,7 @@
     return;
 
   // The options button sits outside the translate_box so that it can be end
-  // packed in hbox_.
+  // packed in hbox().
   GtkWidget* options_menu_button = CreateMenuButton(
       l10n_util::GetStringUTF8(IDS_TRANSLATE_INFOBAR_OPTIONS));
   signals()->Connect(options_menu_button, "clicked",
diff --git a/chrome/browser/ui/gtk/location_bar_view_gtk.cc b/chrome/browser/ui/gtk/location_bar_view_gtk.cc
index 3a012b8..13adaa0 100644
--- a/chrome/browser/ui/gtk/location_bar_view_gtk.cc
+++ b/chrome/browser/ui/gtk/location_bar_view_gtk.cc
@@ -47,7 +47,6 @@
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/content_settings/content_setting_bubble_model.h"
 #include "chrome/browser/ui/content_settings/content_setting_image_model.h"
-#include "chrome/browser/ui/gtk/action_box_button_gtk.h"
 #include "chrome/browser/ui/gtk/bookmarks/bookmark_bubble_gtk.h"
 #include "chrome/browser/ui/gtk/bookmarks/bookmark_utils_gtk.h"
 #include "chrome/browser/ui/gtk/browser_window_gtk.h"
@@ -487,19 +486,6 @@
   // doesn't work, someone is probably calling show_all on our parent box.
   gtk_box_pack_end(GTK_BOX(entry_box_), tab_to_search_hint_, FALSE, FALSE, 0);
 
-  if (extensions::FeatureSwitch::action_box()->IsEnabled()) {
-    // TODO(mpcomplete): should we hide this if ShouldOnlyShowLocation()==true?
-    action_box_button_.reset(new ActionBoxButtonGtk(browser_));
-
-    GtkWidget* alignment = gtk_alignment_new(0, 0, 1, 1);
-    gtk_alignment_set_padding(GTK_ALIGNMENT(alignment),
-                              0, 0, 0, InnerPadding());
-    gtk_container_add(GTK_CONTAINER(alignment), action_box_button_->widget());
-
-    gtk_box_pack_end(GTK_BOX(hbox_.get()), alignment,
-                     FALSE, FALSE, 0);
-  }
-
   if (browser_defaults::bookmarks_enabled && !ShouldOnlyShowLocation()) {
     // Hide the star icon in popups, app windows, etc.
     CreateStarButton();
@@ -1029,11 +1015,6 @@
   page_action_views_[index]->TestActivatePageAction();
 }
 
-void LocationBarViewGtk::TestActionBoxMenuItemSelected(int command_id) {
-  action_box_button_->action_box_button_controller()->
-      ExecuteCommand(command_id, 0);
-}
-
 bool LocationBarViewGtk::GetBookmarkStarVisibility() {
   return starred_;
 }
@@ -1216,7 +1197,7 @@
       GTK_IMAGE(location_icon_image_),
       theme_service_->GetImageNamed(resource_id).ToGdkPixbuf());
 
-  if (toolbar_model_->GetSecurityLevel() == ToolbarModel::EV_SECURE) {
+  if (toolbar_model_->GetSecurityLevel(false) == ToolbarModel::EV_SECURE) {
     if (!gtk_util::IsActingAsRoundedWindow(site_type_event_box_)) {
       // Fun fact: If wee try to make |site_type_event_box_| act as a
       // rounded window while it doesn't have a visible window, GTK interprets
@@ -1622,9 +1603,6 @@
   command_updater_->UpdateCommandEnabled(IDC_BOOKMARK_PAGE, star_enabled);
   command_updater_->UpdateCommandEnabled(IDC_BOOKMARK_PAGE_FROM_STAR,
                                          star_enabled);
-  if (extensions::FeatureSwitch::action_box()->IsEnabled() && !starred_) {
-    star_enabled = false;
-  }
   if (star_enabled) {
     gtk_widget_show_all(star_.get());
     int id = starred_ ? IDR_STAR_LIT : IDR_STAR;
diff --git a/chrome/browser/ui/gtk/location_bar_view_gtk.h b/chrome/browser/ui/gtk/location_bar_view_gtk.h
index c046b53..c886f32 100644
--- a/chrome/browser/ui/gtk/location_bar_view_gtk.h
+++ b/chrome/browser/ui/gtk/location_bar_view_gtk.h
@@ -36,7 +36,6 @@
 #include "ui/base/window_open_disposition.h"
 #include "url/gurl.h"
 
-class ActionBoxButtonGtk;
 class Browser;
 class CommandUpdater;
 class ContentSettingImageModel;
@@ -150,7 +149,6 @@
   virtual ExtensionAction* GetPageAction(size_t index) OVERRIDE;
   virtual ExtensionAction* GetVisiblePageAction(size_t index) OVERRIDE;
   virtual void TestPageActionPressed(size_t index) OVERRIDE;
-  virtual void TestActionBoxMenuItemSelected(int command_id) OVERRIDE;
   virtual bool GetBookmarkStarVisibility() OVERRIDE;
 
   // content::NotificationObserver:
@@ -484,8 +482,6 @@
   // Alignment used to wrap |location_entry_|.
   GtkWidget* location_entry_alignment_;
 
-  scoped_ptr<ActionBoxButtonGtk> action_box_button_;
-
   CommandUpdater* command_updater_;
   ToolbarModel* toolbar_model_;
   Browser* browser_;
diff --git a/chrome/browser/ui/gtk/omnibox/omnibox_view_gtk.cc b/chrome/browser/ui/gtk/omnibox/omnibox_view_gtk.cc
index 5cc63a8..c931846 100644
--- a/chrome/browser/ui/gtk/omnibox/omnibox_view_gtk.cc
+++ b/chrome/browser/ui/gtk/omnibox/omnibox_view_gtk.cc
@@ -457,7 +457,7 @@
       model()->UpdatePermanentText(toolbar_model()->GetText(true));
 
   ToolbarModel::SecurityLevel security_level =
-        toolbar_model()->GetSecurityLevel();
+        toolbar_model()->GetSecurityLevel(false);
   bool changed_security_level = (security_level != security_level_);
   security_level_ = security_level;
 
@@ -1261,7 +1261,7 @@
                      G_CALLBACK(HandleCopyURLClipboardThunk), this);
     gtk_widget_set_sensitive(
         copy_url_menuitem,
-        toolbar_model()->WouldReplaceSearchURLWithSearchTerms() &&
+        toolbar_model()->WouldReplaceSearchURLWithSearchTerms(false) &&
             !model()->user_input_in_progress());
     gtk_widget_show(copy_url_menuitem);
   }
diff --git a/chrome/browser/ui/gtk/status_icons/status_tray_gtk.cc b/chrome/browser/ui/gtk/status_icons/status_tray_gtk.cc
index 04bc250..ecff525 100644
--- a/chrome/browser/ui/gtk/status_icons/status_tray_gtk.cc
+++ b/chrome/browser/ui/gtk/status_icons/status_tray_gtk.cc
@@ -12,7 +12,7 @@
 StatusTrayGtk::~StatusTrayGtk() {
 }
 
-StatusIcon* StatusTrayGtk::CreatePlatformStatusIcon() {
+StatusIcon* StatusTrayGtk::CreatePlatformStatusIcon(StatusIconType type) {
   return new StatusIconGtk();
 }
 
diff --git a/chrome/browser/ui/gtk/status_icons/status_tray_gtk.h b/chrome/browser/ui/gtk/status_icons/status_tray_gtk.h
index cd7a0b4..3e010d7 100644
--- a/chrome/browser/ui/gtk/status_icons/status_tray_gtk.h
+++ b/chrome/browser/ui/gtk/status_icons/status_tray_gtk.h
@@ -15,7 +15,7 @@
 
  protected:
   // Overriden from StatusTray:
-  virtual StatusIcon* CreatePlatformStatusIcon() OVERRIDE;
+  virtual StatusIcon* CreatePlatformStatusIcon(StatusIconType type) OVERRIDE;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(StatusTrayGtk);
diff --git a/chrome/browser/ui/gtk/status_icons/status_tray_gtk_unittest.cc b/chrome/browser/ui/gtk/status_icons/status_tray_gtk_unittest.cc
index 8d96513..3cf40d0 100644
--- a/chrome/browser/ui/gtk/status_icons/status_tray_gtk_unittest.cc
+++ b/chrome/browser/ui/gtk/status_icons/status_tray_gtk_unittest.cc
@@ -29,7 +29,7 @@
 TEST(StatusTrayGtkTest, CreateIcon) {
   // Create an icon, set the images and tooltip, then shut it down.
   StatusTrayGtk tray;
-  StatusIcon* icon = tray.CreateStatusIcon();
+  StatusIcon* icon = tray.CreateStatusIcon(StatusTray::OTHER_ICON);
   ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
   gfx::ImageSkia* image = rb.GetImageSkiaNamed(IDR_STATUS_TRAY_ICON);
   icon->SetImage(*image);
@@ -43,7 +43,8 @@
 TEST(StatusTrayGtkTest, ClickOnIcon) {
   // Create an icon, send a fake click event, make sure observer is called.
   StatusTrayGtk tray;
-  StatusIconGtk* icon = static_cast<StatusIconGtk*>(tray.CreateStatusIcon());
+  StatusIconGtk* icon = static_cast<StatusIconGtk*>(
+      tray.CreateStatusIcon(StatusTray::OTHER_ICON));
   MockStatusIconObserver observer;
   icon->AddObserver(&observer);
   EXPECT_CALL(observer, OnStatusIconClicked());
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 9b98a30..7f419a3 100644
--- a/chrome/browser/ui/gtk/tab_modal_confirm_dialog_gtk.cc
+++ b/chrome/browser/ui/gtk/tab_modal_confirm_dialog_gtk.cc
@@ -31,7 +31,8 @@
 TabModalConfirmDialogGtk::TabModalConfirmDialogGtk(
     TabModalConfirmDialogDelegate* delegate,
     content::WebContents* web_contents)
-    : delegate_(delegate),
+    : web_contents_(web_contents),
+      delegate_(delegate),
       window_(NULL) {
   dialog_ = gtk_vbox_new(FALSE, ui::kContentAreaSpacing);
   GtkWidget* label = gtk_label_new(
@@ -100,7 +101,7 @@
   g_signal_connect(dialog_, "destroy", G_CALLBACK(OnDestroyThunk), this);
 
   window_ = CreateWebContentsModalDialogGtk(dialog_, cancel_);
-  delegate_->set_close_delegate(this);
+  delegate_->set_operations_delegate(this);
 
   WebContentsModalDialogManager* web_contents_modal_dialog_manager =
       WebContentsModalDialogManager::FromWebContents(web_contents);
@@ -108,6 +109,10 @@
 }
 
 TabModalConfirmDialogGtk::~TabModalConfirmDialogGtk() {
+  // Provide a disposition in case the dialog was closed without accepting or
+  // cancelling.
+  delegate_->Cancel();
+
   gtk_widget_destroy(dialog_);
 }
 
@@ -123,6 +128,13 @@
   gtk_widget_destroy(window_);
 }
 
+void TabModalConfirmDialogGtk::SetPreventCloseOnLoadStart(bool prevent) {
+  WebContentsModalDialogManager* web_contents_modal_dialog_manager =
+      WebContentsModalDialogManager::FromWebContents(web_contents_);
+  web_contents_modal_dialog_manager->SetPreventCloseOnLoadStart(window_,
+                                                                prevent);
+}
+
 void TabModalConfirmDialogGtk::OnAccept(GtkWidget* widget) {
   delegate_->Accept();
 }
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 8c7104a..bdbff19 100644
--- a/chrome/browser/ui/gtk/tab_modal_confirm_dialog_gtk.h
+++ b/chrome/browser/ui/gtk/tab_modal_confirm_dialog_gtk.h
@@ -38,8 +38,9 @@
   virtual void AcceptTabModalDialog() OVERRIDE;
   virtual void CancelTabModalDialog() OVERRIDE;
 
-  // TabModalConfirmDialogCloseDelegate:
+  // TabModalConfirmDialogOperationsDelegate:
   virtual void CloseDialog() OVERRIDE;
+  virtual void SetPreventCloseOnLoadStart(bool prevent) OVERRIDE;
 
   // Callbacks:
   CHROMEGTK_CALLBACK_0(TabModalConfirmDialogGtk, void, OnAccept);
@@ -47,6 +48,8 @@
   CHROMEGTK_CALLBACK_0(TabModalConfirmDialogGtk, void, OnDestroy);
   CHROMEGTK_CALLBACK_0(TabModalConfirmDialogGtk, void, OnLinkClicked);
 
+  content::WebContents* web_contents_;
+
   scoped_ptr<TabModalConfirmDialogDelegate> delegate_;
 
   GtkWidget* dialog_;
diff --git a/chrome/browser/ui/hung_plugin_tab_helper.cc b/chrome/browser/ui/hung_plugin_tab_helper.cc
index 648cba4..1428d1a 100644
--- a/chrome/browser/ui/hung_plugin_tab_helper.cc
+++ b/chrome/browser/ui/hung_plugin_tab_helper.cc
@@ -131,8 +131,8 @@
 
 class HungPluginInfoBarDelegate : public ConfirmInfoBarDelegate {
  public:
-  // Creates a hung plugin delegate and adds it to |infobar_service|.  Returns
-  // the delegate if it was successfully added.
+  // Creates a hung plugin infobar delegate and adds it to |infobar_service|.
+  // Returns the delegate if it was successfully added.
   static HungPluginInfoBarDelegate* Create(InfoBarService* infobar_service,
                                            HungPluginTabHelper* helper,
                                            int plugin_child_id,
@@ -234,8 +234,7 @@
   base::Timer timer;
 
  private:
-  // Delay in seconds before re-showing the hung plugin message. This will be
-  // increased each time.
+  // Initial delay in seconds before re-showing the hung plugin message.
   static const int kInitialReshowDelaySec;
 
   // Since the scope of the timer manages our callback, this struct should
@@ -329,7 +328,6 @@
     const content::NotificationSource& source,
     const content::NotificationDetails& details) {
   DCHECK_EQ(chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED, type);
-
   // Note: do not dereference. The InfoBarContainer will delete the object when
   // it gets this notification, we only remove our tracking info, if we have
   // any.
@@ -338,7 +336,6 @@
   // InfoBars own their delegates.
   InfoBarDelegate* infobar =
       content::Details<InfoBarRemovedDetails>(details)->first;
-
   for (PluginStateMap::iterator i = hung_plugins_.begin();
        i != hung_plugins_.end(); ++i) {
     PluginState* state = i->second.get();
@@ -421,9 +418,8 @@
     return;
 
   DCHECK(!state->infobar);
-  state->infobar =
-      HungPluginInfoBarDelegate::Create(infobar_service, this, child_id,
-                                        state->name);
+  state->infobar = HungPluginInfoBarDelegate::Create(infobar_service, this,
+                                                     child_id, state->name);
 }
 
 void HungPluginTabHelper::CloseBar(PluginState* state) {
diff --git a/chrome/browser/ui/libgtk2ui/app_indicator_icon.cc b/chrome/browser/ui/libgtk2ui/app_indicator_icon.cc
new file mode 100644
index 0000000..ff4b79f
--- /dev/null
+++ b/chrome/browser/ui/libgtk2ui/app_indicator_icon.cc
@@ -0,0 +1,383 @@
+// Copyright 2013 The Chromium Authors. 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/app_indicator_icon.h"
+
+#include <gtk/gtk.h>
+#include <dlfcn.h>
+
+#include "base/bind.h"
+#include "base/file_util.h"
+#include "base/memory/ref_counted_memory.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/threading/sequenced_worker_pool.h"
+#include "chrome/browser/ui/libgtk2ui/menu_util.h"
+#include "content/public/browser/browser_thread.h"
+#include "ui/base/models/menu_model.h"
+#include "ui/gfx/image/image_skia.h"
+
+namespace {
+
+typedef enum {
+  APP_INDICATOR_CATEGORY_APPLICATION_STATUS,
+  APP_INDICATOR_CATEGORY_COMMUNICATIONS,
+  APP_INDICATOR_CATEGORY_SYSTEM_SERVICES,
+  APP_INDICATOR_CATEGORY_HARDWARE,
+  APP_INDICATOR_CATEGORY_OTHER
+} AppIndicatorCategory;
+
+typedef enum {
+  APP_INDICATOR_STATUS_PASSIVE,
+  APP_INDICATOR_STATUS_ACTIVE,
+  APP_INDICATOR_STATUS_ATTENTION
+} AppIndicatorStatus;
+
+typedef AppIndicator* (*app_indicator_new_func)(const gchar* id,
+                                                const gchar* icon_name,
+                                                AppIndicatorCategory category);
+
+typedef AppIndicator* (*app_indicator_new_with_path_func)(
+    const gchar* id,
+    const gchar* icon_name,
+    AppIndicatorCategory category,
+    const gchar* icon_theme_path);
+
+typedef void (*app_indicator_set_status_func)(AppIndicator* self,
+                                              AppIndicatorStatus status);
+
+typedef void (*app_indicator_set_attention_icon_full_func)(
+    AppIndicator* self,
+    const gchar* icon_name,
+    const gchar* icon_desc);
+
+typedef void (*app_indicator_set_menu_func)(AppIndicator* self, GtkMenu* menu);
+
+typedef void (*app_indicator_set_icon_full_func)(AppIndicator* self,
+                                                 const gchar* icon_name,
+                                                 const gchar* icon_desc);
+
+typedef void (*app_indicator_set_icon_theme_path_func)(
+    AppIndicator* self,
+    const gchar* icon_theme_path);
+
+bool attempted_load = false;
+bool opened = false;
+
+// Retrieved functions from libappindicator.
+app_indicator_new_func app_indicator_new = NULL;
+app_indicator_new_with_path_func app_indicator_new_with_path = NULL;
+app_indicator_set_status_func app_indicator_set_status = NULL;
+app_indicator_set_attention_icon_full_func
+    app_indicator_set_attention_icon_full = NULL;
+app_indicator_set_menu_func app_indicator_set_menu = NULL;
+app_indicator_set_icon_full_func app_indicator_set_icon_full = NULL;
+app_indicator_set_icon_theme_path_func app_indicator_set_icon_theme_path = NULL;
+
+void EnsureMethodsLoaded() {
+
+  if (attempted_load)
+    return;
+  attempted_load = true;
+
+  void* indicator_lib = dlopen("libappindicator.so", RTLD_LAZY);
+  if (!indicator_lib) {
+    indicator_lib = dlopen("libappindicator.so.1", RTLD_LAZY);
+  }
+  if (!indicator_lib) {
+    indicator_lib = dlopen("libappindicator.so.0", RTLD_LAZY);
+  }
+  if (!indicator_lib) {
+    return;
+  }
+
+  opened = true;
+
+  app_indicator_new = reinterpret_cast<app_indicator_new_func>(
+      dlsym(indicator_lib, "app_indicator_new"));
+
+  app_indicator_new_with_path =
+      reinterpret_cast<app_indicator_new_with_path_func>(
+          dlsym(indicator_lib, "app_indicator_new_with_path"));
+
+  app_indicator_set_status = reinterpret_cast<app_indicator_set_status_func>(
+      dlsym(indicator_lib, "app_indicator_set_status"));
+
+  app_indicator_set_attention_icon_full =
+      reinterpret_cast<app_indicator_set_attention_icon_full_func>(
+          dlsym(indicator_lib, "app_indicator_set_attention_icon_full"));
+
+  app_indicator_set_menu = reinterpret_cast<app_indicator_set_menu_func>(
+      dlsym(indicator_lib, "app_indicator_set_menu"));
+
+  app_indicator_set_icon_full =
+      reinterpret_cast<app_indicator_set_icon_full_func>(
+          dlsym(indicator_lib, "app_indicator_set_icon_full"));
+
+  app_indicator_set_icon_theme_path =
+      reinterpret_cast<app_indicator_set_icon_theme_path_func>(
+          dlsym(indicator_lib, "app_indicator_set_icon_theme_path"));
+}
+
+}  // namespace
+
+namespace libgtk2ui {
+
+AppIndicatorIcon::AppIndicatorIcon(std::string id)
+    : id_(id),
+      icon_(NULL),
+      gtk_menu_(NULL),
+      menu_model_(NULL),
+      icon_change_count_(0),
+      block_activation_(false),
+      has_click_action_replacement_(false) {
+  EnsureMethodsLoaded();
+}
+AppIndicatorIcon::~AppIndicatorIcon() {
+  if (icon_) {
+    app_indicator_set_status(icon_, APP_INDICATOR_STATUS_PASSIVE);
+    if (menu_model_)
+      menu_model_->MenuClosed();
+    if (gtk_menu_)
+      DestroyMenu();
+    g_object_unref(icon_);
+    content::BrowserThread::GetBlockingPool()->PostTask(
+        FROM_HERE,
+        base::Bind(&AppIndicatorIcon::DeletePath, icon_file_path_.DirName()));
+  }
+}
+
+bool AppIndicatorIcon::CouldOpen() {
+  EnsureMethodsLoaded();
+  return opened;
+}
+
+void AppIndicatorIcon::SetImage(const gfx::ImageSkia& image) {
+  if (opened) {
+    ++icon_change_count_;
+    gfx::ImageSkia safe_image = gfx::ImageSkia(image);
+    safe_image.MakeThreadSafe();
+    base::PostTaskAndReplyWithResult(
+        content::BrowserThread::GetBlockingPool()
+            ->GetTaskRunnerWithShutdownBehavior(
+                  base::SequencedWorkerPool::SKIP_ON_SHUTDOWN).get(),
+        FROM_HERE,
+        base::Bind(&AppIndicatorIcon::CreateTempImageFile,
+                   safe_image,
+                   icon_change_count_,
+                   id_),
+        base::Bind(&AppIndicatorIcon::SetImageFromFile,
+                   base::Unretained(this)));
+  }
+}
+
+void AppIndicatorIcon::SetPressedImage(const gfx::ImageSkia& image) {
+  // Ignore pressed images, since the standard on Linux is to not highlight
+  // pressed status icons.
+}
+
+void AppIndicatorIcon::SetToolTip(const string16& tool_tip) {
+  // App-indicators don't support tool-tips. Ignore call.
+}
+
+void AppIndicatorIcon::SetClickActionLabel(const string16& label) {
+  click_action_label_ = UTF16ToUTF8(label);
+
+  // If the menu item has already been created, then find the menu item and
+  // change it's label.
+  if (has_click_action_replacement_) {
+    GList* children = gtk_container_get_children(GTK_CONTAINER(gtk_menu_));
+    for (GList* child = children; child; child = g_list_next(child))
+      if (g_object_get_data(G_OBJECT(child->data), "click-action-item") !=
+          NULL) {
+        gtk_menu_item_set_label(GTK_MENU_ITEM(child->data),
+                                click_action_label_.c_str());
+        break;
+      }
+    g_list_free(children);
+  } else if (icon_) {
+    CreateClickActionReplacement();
+    app_indicator_set_menu(icon_, GTK_MENU(gtk_menu_));
+  }
+}
+
+void AppIndicatorIcon::UpdatePlatformContextMenu(ui::MenuModel* model) {
+  if (!opened)
+    return;
+
+  if (gtk_menu_) {
+    DestroyMenu();
+    has_click_action_replacement_ = false;
+  }
+  menu_model_ = model;
+
+  // If icon doesn't exist now it's okay, the menu will be set later along with
+  // the image. Both an icon and a menu are required to show an app indicator.
+  if (model && icon_)
+    SetMenu();
+}
+
+void AppIndicatorIcon::SetImageFromFile(base::FilePath icon_file_path) {
+  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+  if (!icon_file_path.empty()) {
+    base::FilePath old_path = icon_file_path_;
+    icon_file_path_ = icon_file_path;
+
+    std::string icon_name =
+        icon_file_path_.BaseName().RemoveExtension().value();
+    std::string icon_dir = icon_file_path_.DirName().value();
+    if (!icon_) {
+      icon_ =
+          app_indicator_new_with_path(id_.c_str(),
+                                      icon_name.c_str(),
+                                      APP_INDICATOR_CATEGORY_APPLICATION_STATUS,
+                                      icon_dir.c_str());
+      app_indicator_set_status(icon_, APP_INDICATOR_STATUS_ACTIVE);
+      if (menu_model_) {
+        SetMenu();
+      } else if (!click_action_label_.empty()) {
+        CreateClickActionReplacement();
+        app_indicator_set_menu(icon_, GTK_MENU(gtk_menu_));
+      }
+    } else {
+      // Currently we are creating a new temp directory every time the icon is
+      // set. So we need to set the directory each time.
+      app_indicator_set_icon_theme_path(icon_, icon_dir.c_str());
+      app_indicator_set_icon_full(icon_, icon_name.c_str(), "icon");
+
+      // Delete previous icon directory.
+      content::BrowserThread::GetBlockingPool()->PostTask(
+          FROM_HERE,
+          base::Bind(&AppIndicatorIcon::DeletePath, old_path.DirName()));
+    }
+  }
+}
+
+void AppIndicatorIcon::SetMenu() {
+  gtk_menu_ = gtk_menu_new();
+  BuildSubmenuFromModel(menu_model_,
+                        gtk_menu_,
+                        G_CALLBACK(OnMenuItemActivatedThunk),
+                        &block_activation_,
+                        this);
+  if (!click_action_label_.empty())
+    CreateClickActionReplacement();
+  UpdateMenu();
+  menu_model_->MenuWillShow();
+  app_indicator_set_menu(icon_, GTK_MENU(gtk_menu_));
+}
+
+void AppIndicatorIcon::CreateClickActionReplacement() {
+  GtkWidget* menu_item = NULL;
+
+  // If a menu doesn't exist create one just for the click action replacement.
+  if (!gtk_menu_) {
+    gtk_menu_ = gtk_menu_new();
+  } else {
+    // Add separator before the other menu items.
+    menu_item = gtk_separator_menu_item_new();
+    gtk_widget_show(menu_item);
+    gtk_menu_shell_prepend(GTK_MENU_SHELL(gtk_menu_), menu_item);
+  }
+
+  // Add "click replacement menu item".
+  menu_item = gtk_menu_item_new_with_mnemonic(click_action_label_.c_str());
+  g_object_set_data(
+      G_OBJECT(menu_item), "click-action-item", GINT_TO_POINTER(1));
+  g_signal_connect(menu_item, "activate", G_CALLBACK(OnClickThunk), this);
+  gtk_widget_show(menu_item);
+  gtk_menu_shell_prepend(GTK_MENU_SHELL(gtk_menu_), menu_item);
+
+  has_click_action_replacement_ = true;
+}
+
+void AppIndicatorIcon::DestroyMenu() {
+  if (menu_model_)
+    menu_model_->MenuClosed();
+  gtk_widget_destroy(gtk_menu_);
+  gtk_menu_ = NULL;
+  menu_model_ = NULL;
+}
+
+base::FilePath AppIndicatorIcon::CreateTempImageFile(gfx::ImageSkia image,
+                                                     int icon_change_count,
+                                                     std::string id) {
+  scoped_refptr<base::RefCountedMemory> png_data =
+      gfx::Image(image).As1xPNGBytes();
+  if (png_data->size() == 0) {
+    // If the bitmap could not be encoded to PNG format, skip it.
+    LOG(WARNING) << "Could not encode icon";
+    return base::FilePath();
+  }
+
+  base::FilePath temp_dir;
+  base::FilePath new_file_path;
+
+  // Create a new temporary directory for each image since using a single
+  // temporary directory seems to have issues when changing icons in quick
+  // succession.
+  if (!file_util::CreateNewTempDirectory("", &temp_dir))
+    return base::FilePath();
+  new_file_path =
+      temp_dir.Append(id + base::StringPrintf("_%d.png", icon_change_count));
+  int bytes_written =
+      file_util::WriteFile(new_file_path,
+                           reinterpret_cast<const char*>(png_data->front()),
+                           png_data->size());
+
+  if (bytes_written != static_cast<int>(png_data->size())) {
+    return base::FilePath();
+  }
+
+  return new_file_path;
+}
+
+void AppIndicatorIcon::DeletePath(base::FilePath icon_file_path) {
+  if (!icon_file_path.empty()) {
+    base::DeleteFile(icon_file_path, true);
+  }
+}
+
+void AppIndicatorIcon::UpdateMenu() {
+  gtk_container_foreach(
+      GTK_CONTAINER(gtk_menu_), SetMenuItemInfo, &block_activation_);
+}
+
+void AppIndicatorIcon::OnClick(GtkWidget* menu_item) {
+  if (delegate())
+    delegate()->OnClick();
+}
+
+void AppIndicatorIcon::OnMenuItemActivated(GtkWidget* menu_item) {
+  if (block_activation_)
+    return;
+
+  ui::MenuModel* model = ModelForMenuItem(GTK_MENU_ITEM(menu_item));
+
+  if (!model) {
+    // There won't be a model for "native" submenus like the "Input Methods"
+    // context menu. We don't need to handle activation messages for submenus
+    // anyway, so we can just return here.
+    DCHECK(gtk_menu_item_get_submenu(GTK_MENU_ITEM(menu_item)));
+    return;
+  }
+
+  // The activate signal is sent to radio items as they get deselected;
+  // ignore it in this case.
+  if (GTK_IS_RADIO_MENU_ITEM(menu_item) &&
+      !gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menu_item))) {
+    return;
+  }
+
+  int id;
+  if (!GetMenuItemID(menu_item, &id))
+    return;
+
+  // The menu item can still be activated by hotkeys even if it is disabled.
+  if (menu_model_->IsEnabledAt(id))
+    ExecuteCommand(model, id);
+  UpdateMenu();
+}
+
+}  // namespace libgtk2ui
diff --git a/chrome/browser/ui/libgtk2ui/app_indicator_icon.h b/chrome/browser/ui/libgtk2ui/app_indicator_icon.h
new file mode 100644
index 0000000..33bfd5e
--- /dev/null
+++ b/chrome/browser/ui/libgtk2ui/app_indicator_icon.h
@@ -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.
+
+#ifndef CHROME_BROWSER_UI_LIBGTK2UI_APP_INDICATOR_ICON_H_
+#define CHROME_BROWSER_UI_LIBGTK2UI_APP_INDICATOR_ICON_H_
+
+#include "base/files/file_path.h"
+#include "chrome/browser/ui/libgtk2ui/gtk2_signal.h"
+#include "ui/linux_ui/status_icon_linux.h"
+
+typedef struct _AppIndicator AppIndicator;
+typedef struct _GtkWidget GtkWidget;
+
+namespace gfx {
+class ImageSkia;
+}
+
+namespace libgtk2ui {
+
+class AppIndicatorIcon : public StatusIconLinux {
+ public:
+  // The id uniquely identifies the new status icon from other chrome status
+  // icons.
+  explicit AppIndicatorIcon(std::string id);
+  virtual ~AppIndicatorIcon();
+
+  // Indicates whether libappindicator so could be opened.
+  static bool CouldOpen();
+
+  // Overridden from StatusIcon:
+  virtual void SetImage(const gfx::ImageSkia& image) OVERRIDE;
+  virtual void SetPressedImage(const gfx::ImageSkia& image) OVERRIDE;
+  virtual void SetToolTip(const string16& tool_tip) OVERRIDE;
+  virtual void SetClickActionLabel(const string16& label) OVERRIDE;
+
+ protected:
+  // Overridden from StatusIcon.
+  virtual void UpdatePlatformContextMenu(ui::MenuModel* menu) OVERRIDE;
+
+ private:
+  void SetImageFromFile(base::FilePath icon_file_path);
+  void SetMenu();
+
+  // Adds a menu item to the top of the existing gtk_menu as a replacement for
+  // the status icon click action or creates a new gtk menu with the menu item
+  // if a menu doesn't exist. Clicking on this menu item should simulate a
+  // status icon click by despatching a click event.
+  void CreateClickActionReplacement();
+  void DestroyMenu();
+
+  static base::FilePath CreateTempImageFile(gfx::ImageSkia image,
+                                            int icon_change_count,
+                                            std::string id);
+  static void DeletePath(base::FilePath icon_file_path);
+
+  // Updates all the enabled/checked states and the dynamic labels.
+  void UpdateMenu();
+
+  // Callback for when the status icon click replacement menu item is clicked.
+  CHROMEGTK_CALLBACK_0(AppIndicatorIcon, void, OnClick);
+
+  // Callback for when a menu item is clicked.
+  CHROMEGTK_CALLBACK_0(AppIndicatorIcon, void, OnMenuItemActivated);
+
+  std::string id_;
+  std::string click_action_label_;
+
+  // Gtk status icon wrapper
+  AppIndicator* icon_;
+
+  GtkWidget* gtk_menu_;
+  ui::MenuModel* menu_model_;
+
+  base::FilePath icon_file_path_;
+  int icon_change_count_;
+  bool block_activation_;
+  bool has_click_action_replacement_;
+};
+
+}  // namespace libgtk2ui
+
+#endif  // CHROME_BROWSER_UI_LIBGTK2UI_APP_INDICATOR_ICON_H_
diff --git a/chrome/browser/ui/libgtk2ui/gtk2_ui.cc b/chrome/browser/ui/libgtk2ui/gtk2_ui.cc
index de66141..4167edc 100644
--- a/chrome/browser/ui/libgtk2ui/gtk2_ui.cc
+++ b/chrome/browser/ui/libgtk2ui/gtk2_ui.cc
@@ -12,7 +12,9 @@
 #include "base/logging.h"
 #include "base/nix/mime_util_xdg.h"
 #include "base/stl_util.h"
+#include "base/strings/stringprintf.h"
 #include "chrome/browser/themes/theme_properties.h"
+#include "chrome/browser/ui/libgtk2ui/app_indicator_icon.h"
 #include "chrome/browser/ui/libgtk2ui/chrome_gtk_frame.h"
 #include "chrome/browser/ui/libgtk2ui/gtk2_util.h"
 #include "chrome/browser/ui/libgtk2ui/native_theme_gtk2.h"
@@ -49,6 +51,12 @@
 
 namespace {
 
+// Prefix for app indicator ids
+const char kAppIndicatorIdPrefix[] = "chrome_app_indicator_";
+
+// Number of app indicators used (used as part of app-indicator id).
+int indicators_count;
+
 // The size of the rendered toolbar image.
 const int kToolbarImageWidth = 64;
 const int kToolbarImageHeight = 128;
@@ -304,6 +312,8 @@
   // style-set signal handler.
   LoadGtkValues();
   SetXDGIconTheme();
+
+  indicators_count = 0;
 }
 
 Gtk2UI::~Gtk2UI() {
@@ -381,6 +391,20 @@
     unity::SetProgressFraction(percentage);
 }
 
+bool Gtk2UI::IsStatusIconSupported() const {
+  return AppIndicatorIcon::CouldOpen();
+}
+
+scoped_ptr<StatusIconLinux> Gtk2UI::CreateLinuxStatusIcon() const {
+  if (AppIndicatorIcon::CouldOpen()) {
+    ++indicators_count;
+    return scoped_ptr<StatusIconLinux>(new AppIndicatorIcon(
+        base::StringPrintf("%s%d", kAppIndicatorIdPrefix, indicators_count)));
+  } else {
+    return scoped_ptr<StatusIconLinux>();
+  }
+}
+
 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 b1db13a..69a7dde 100644
--- a/chrome/browser/ui/libgtk2ui/gtk2_ui.h
+++ b/chrome/browser/ui/libgtk2ui/gtk2_ui.h
@@ -47,6 +47,8 @@
   virtual bool GetDefaultUsesSystemTheme() const OVERRIDE;
   virtual void SetDownloadCount(int count) const OVERRIDE;
   virtual void SetProgressFraction(float percentage) const OVERRIDE;
+  virtual bool IsStatusIconSupported() const OVERRIDE;
+  virtual scoped_ptr<StatusIconLinux> CreateLinuxStatusIcon() 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 eec6b1a..107f2ee 100644
--- a/chrome/browser/ui/libgtk2ui/gtk2_util.cc
+++ b/chrome/browser/ui/libgtk2ui/gtk2_util.cc
@@ -8,11 +8,10 @@
 
 #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"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "ui/gfx/canvas.h"
+#include "ui/base/accelerators/accelerator.h"
+#include "ui/base/events/event_constants.h"
+#include "ui/base/keycodes/keyboard_code_conversion_x.cc"
 #include "ui/gfx/size.h"
 
 namespace {
@@ -36,6 +35,33 @@
   }
 }
 
+// Replaces all ampersands (as used in our grd files to indicate mnemonics)
+// to |target|, except ampersands appearing in pairs which are replaced by
+// a single ampersand. Any underscores get replaced with two underscores as
+// is needed by GTK.
+std::string ConvertAmpersandsTo(const std::string& label,
+                                const std::string& target) {
+  std::string ret;
+  ret.reserve(label.length() * 2);
+  for (size_t i = 0; i < label.length(); ++i) {
+    if ('_' == label[i]) {
+      ret.push_back('_');
+      ret.push_back('_');
+    } else if ('&' == label[i]) {
+      if (i + 1 < label.length() && '&' == label[i + 1]) {
+        ret.push_back('&');
+        ++i;
+      } else {
+        ret.append(target);
+      }
+    } else {
+      ret.push_back(label[i]);
+    }
+  }
+
+  return ret;
+}
+
 }  // namespace
 
 namespace libgtk2ui {
@@ -61,60 +87,45 @@
 #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
-  // recompiling half of our skia extensions with gtk support, which we can't
-  // do in this build.
-  DCHECK_EQ(GDK_COLORSPACE_RGB, gdk_pixbuf_get_colorspace(pixbuf));
+void SetAlwaysShowImage(GtkWidget* image_menu_item) {
+  gtk_image_menu_item_set_always_show_image(
+      GTK_IMAGE_MENU_ITEM(image_menu_item), TRUE);
+}
 
-  int n_channels = gdk_pixbuf_get_n_channels(pixbuf);
-  int w = gdk_pixbuf_get_width(pixbuf);
-  int h = gdk_pixbuf_get_height(pixbuf);
+std::string ConvertAcceleratorsFromWindowsStyle(const std::string& label) {
+  return ConvertAmpersandsTo(label, "_");
+}
 
-  SkBitmap ret;
-  ret.setConfig(SkBitmap::kARGB_8888_Config, w, h);
-  ret.allocPixels();
-  ret.eraseColor(0);
+guint GetGdkKeyCodeForAccelerator(const ui::Accelerator& accelerator) {
+  // The second parameter is false because accelerator keys are expressed in
+  // terms of the non-shift-modified key.
+  return XKeysymForWindowsKeyCode(accelerator.key_code(), false);
+}
 
-  uint32_t* skia_data = static_cast<uint32_t*>(ret.getAddr(0, 0));
+GdkModifierType GetGdkModifierForAccelerator(
+    const ui::Accelerator& accelerator) {
+  int event_flag = accelerator.modifiers();
+  int modifier = 0;
+  if (event_flag & ui::EF_SHIFT_DOWN)
+    modifier |= GDK_SHIFT_MASK;
+  if (event_flag & ui::EF_CONTROL_DOWN)
+    modifier |= GDK_CONTROL_MASK;
+  if (event_flag & ui::EF_ALT_DOWN)
+    modifier |= GDK_MOD1_MASK;
+  return static_cast<GdkModifierType>(modifier);
+}
 
-  if (n_channels == 4) {
-    int total_length = w * h;
-    guchar* gdk_pixels = gdk_pixbuf_get_pixels(pixbuf);
-
-    // Now here's the trick: we need to convert the gdk data (which is RGBA and
-    // isn't premultiplied) to skia (which can be anything and premultiplied).
-    for (int i = 0; i < total_length; ++i, gdk_pixels += 4) {
-      const unsigned char& red = gdk_pixels[0];
-      const unsigned char& green = gdk_pixels[1];
-      const unsigned char& blue = gdk_pixels[2];
-      const unsigned char& alpha = gdk_pixels[3];
-
-      skia_data[i] = SkPreMultiplyARGB(alpha, red, green, blue);
-    }
-  } else if (n_channels == 3) {
-    // Because GDK makes rowstrides word aligned, we need to do something a bit
-    // more complex when a pixel isn't perfectly a word of memory.
-    int rowstride = gdk_pixbuf_get_rowstride(pixbuf);
-    guchar* gdk_pixels = gdk_pixbuf_get_pixels(pixbuf);
-    for (int y = 0; y < h; ++y) {
-      int row = y * rowstride;
-
-      for (int x = 0; x < w; ++x) {
-        guchar* pixel = gdk_pixels + row + (x * 3);
-        const unsigned char& red = pixel[0];
-        const unsigned char& green = pixel[1];
-        const unsigned char& blue = pixel[2];
-
-        skia_data[y * w + x] = SkPreMultiplyARGB(255, red, green, blue);
-      }
-    }
-  } else {
-    NOTREACHED();
-  }
-
-  return ret;
+int EventFlagsFromGdkState(guint state) {
+  int flags = ui::EF_NONE;
+  flags |= (state & GDK_LOCK_MASK) ? ui::EF_CAPS_LOCK_DOWN : ui::EF_NONE;
+  flags |= (state & GDK_CONTROL_MASK) ? ui::EF_CONTROL_DOWN : ui::EF_NONE;
+  flags |= (state & GDK_SHIFT_MASK) ? ui::EF_SHIFT_DOWN : ui::EF_NONE;
+  flags |= (state & GDK_MOD1_MASK) ? ui::EF_ALT_DOWN : ui::EF_NONE;
+  flags |= (state & GDK_BUTTON1_MASK) ? ui::EF_LEFT_MOUSE_BUTTON : ui::EF_NONE;
+  flags |=
+      (state & GDK_BUTTON2_MASK) ? ui::EF_MIDDLE_MOUSE_BUTTON : ui::EF_NONE;
+  flags |= (state & GDK_BUTTON3_MASK) ? ui::EF_RIGHT_MOUSE_BUTTON : ui::EF_NONE;
+  return flags;
 }
 
 }  // namespace libgtk2ui
diff --git a/chrome/browser/ui/libgtk2ui/gtk2_util.h b/chrome/browser/ui/libgtk2ui/gtk2_util.h
index 77a1cbf..ca5274c 100644
--- a/chrome/browser/ui/libgtk2ui/gtk2_util.h
+++ b/chrome/browser/ui/libgtk2ui/gtk2_util.h
@@ -5,10 +5,9 @@
 #ifndef CHROME_BROWSER_UI_LIBGTK2UI_GTK2_UTIL_H_
 #define CHROME_BROWSER_UI_LIBGTK2UI_GTK2_UTIL_H_
 
+#include <gtk/gtk.h>
 #include <string>
 
-typedef struct _GdkPixbuf GdkPixbuf;
-
 class CommandLine;
 class SkBitmap;
 
@@ -16,6 +15,10 @@
 class Environment;
 }
 
+namespace ui {
+class Accelerator;
+}
+
 namespace libgtk2ui {
 
 void GtkInitFromCommandLine(const CommandLine& command_line);
@@ -23,7 +26,22 @@
 // Returns the name of the ".desktop" file associated with our running process.
 std::string GetDesktopName(base::Environment* env);
 
-const SkBitmap GdkPixbufToImageSkia(GdkPixbuf* pixbuf);
+// Show the image for the given menu item, even if the user's default is to not
+// show images. Only to be used for favicons or other menus where the image is
+// crucial to its functionality.
+void SetAlwaysShowImage(GtkWidget* image_menu_item);
+
+// Change windows accelerator style to GTK style. (GTK uses _ for
+// accelerators.  Windows uses & with && as an escape for &.)
+std::string ConvertAcceleratorsFromWindowsStyle(const std::string& label);
+
+guint GetGdkKeyCodeForAccelerator(const ui::Accelerator& accelerator);
+
+GdkModifierType GetGdkModifierForAccelerator(
+    const ui::Accelerator& accelerator);
+
+// Translates event flags into plaform independent event flags.
+int EventFlagsFromGdkState(guint state);
 
 }  // namespace libgtk2ui
 
diff --git a/chrome/browser/ui/libgtk2ui/libgtk2ui.gyp b/chrome/browser/ui/libgtk2ui/libgtk2ui.gyp
index efa61e9..d204857 100644
--- a/chrome/browser/ui/libgtk2ui/libgtk2ui.gyp
+++ b/chrome/browser/ui/libgtk2ui/libgtk2ui.gyp
@@ -33,6 +33,8 @@
       # the normal, global gtk exclusion rules, as we are otherwise using gtk
       # in a non-gtk build.
       'sources': [
+        'app_indicator_icon.cc',
+        'app_indicator_icon.h',
         'chrome_gtk_frame.cc',
         'chrome_gtk_frame.h',
         'gtk2_ui.cc',
@@ -40,6 +42,8 @@
         'gtk2_util.cc',
         'gtk2_util.h',
         'libgtk2ui_export.h',
+        'menu_util.cc',
+        'menu_util.h',
         'native_theme_gtk2.cc',
         'native_theme_gtk2.h',
         'owned_widget_gtk2.cc',
diff --git a/chrome/browser/ui/libgtk2ui/menu_util.cc b/chrome/browser/ui/libgtk2ui/menu_util.cc
new file mode 100644
index 0000000..90bb54e
--- /dev/null
+++ b/chrome/browser/ui/libgtk2ui/menu_util.cc
@@ -0,0 +1,260 @@
+// Copyright 2013 The Chromium Authors. 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/menu_util.h"
+
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/app/chrome_command_ids.h"
+#include "chrome/browser/ui/libgtk2ui/gtk2_util.h"
+#include "chrome/browser/ui/libgtk2ui/skia_utils_gtk2.h"
+#include "ui/base/accelerators/accelerator.h"
+#include "ui/base/models/menu_model.h"
+
+namespace libgtk2ui {
+
+GtkWidget* BuildMenuItemWithImage(const std::string& label, GtkWidget* image) {
+  GtkWidget* menu_item = gtk_image_menu_item_new_with_mnemonic(label.c_str());
+  gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item), image);
+  return menu_item;
+}
+
+GtkWidget* BuildMenuItemWithImage(const std::string& label,
+                                  const gfx::Image& icon) {
+  GdkPixbuf* pixbuf = GdkPixbufFromSkBitmap(*icon.ToSkBitmap());
+
+  GtkWidget* menu_item =
+      BuildMenuItemWithImage(label, gtk_image_new_from_pixbuf(pixbuf));
+  g_object_unref(pixbuf);
+  return menu_item;
+}
+
+GtkWidget* BuildMenuItemWithLabel(const std::string& label) {
+  return gtk_menu_item_new_with_mnemonic(label.c_str());
+}
+
+ui::MenuModel* ModelForMenuItem(GtkMenuItem* menu_item) {
+  return reinterpret_cast<ui::MenuModel*>(
+      g_object_get_data(G_OBJECT(menu_item), "model"));
+}
+
+GtkWidget* AppendMenuItemToMenu(int index,
+                                ui::MenuModel* model,
+                                GtkWidget* menu_item,
+                                GtkWidget* menu,
+                                bool connect_to_activate,
+                                GCallback item_activated_cb,
+                                void* this_ptr) {
+  // Set the ID of a menu item.
+  // Add 1 to the menu_id to avoid setting zero (null) to "menu-id".
+  g_object_set_data(G_OBJECT(menu_item), "menu-id", GINT_TO_POINTER(index + 1));
+
+  // Native menu items do their own thing, so only selectively listen for the
+  // activate signal.
+  if (connect_to_activate) {
+    g_signal_connect(menu_item, "activate", item_activated_cb, this_ptr);
+  }
+
+  // AppendMenuItemToMenu is used both internally when we control menu creation
+  // from a model (where the model can choose to hide certain menu items), and
+  // with immediate commands which don't provide the option.
+  if (model) {
+    if (model->IsVisibleAt(index))
+      gtk_widget_show(menu_item);
+  } else {
+    gtk_widget_show(menu_item);
+  }
+  gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
+  return menu_item;
+}
+
+bool GetMenuItemID(GtkWidget* menu_item, int* menu_id) {
+  gpointer id_ptr = g_object_get_data(G_OBJECT(menu_item), "menu-id");
+  if (id_ptr != NULL) {
+    *menu_id = GPOINTER_TO_INT(id_ptr) - 1;
+    return true;
+  }
+
+  return false;
+}
+
+void ExecuteCommand(ui::MenuModel* model, int id) {
+  GdkEvent* event = gtk_get_current_event();
+  int event_flags = 0;
+
+  if (event && event->type == GDK_BUTTON_RELEASE)
+    event_flags = EventFlagsFromGdkState(event->button.state);
+  model->ActivatedAt(id, event_flags);
+
+  if (event)
+    gdk_event_free(event);
+}
+
+void BuildSubmenuFromModel(ui::MenuModel* model,
+                           GtkWidget* menu,
+                           GCallback item_activated_cb,
+                           bool* block_activation,
+                           void* this_ptr) {
+  std::map<int, GtkWidget*> radio_groups;
+  GtkWidget* menu_item = NULL;
+  for (int i = 0; i < model->GetItemCount(); ++i) {
+    gfx::Image icon;
+    std::string label =
+        ConvertAcceleratorsFromWindowsStyle(UTF16ToUTF8(model->GetLabelAt(i)));
+
+    bool connect_to_activate = true;
+
+    switch (model->GetTypeAt(i)) {
+      case ui::MenuModel::TYPE_SEPARATOR:
+        menu_item = gtk_separator_menu_item_new();
+        break;
+
+      case ui::MenuModel::TYPE_CHECK:
+        menu_item = gtk_check_menu_item_new_with_mnemonic(label.c_str());
+        break;
+
+      case ui::MenuModel::TYPE_RADIO: {
+        std::map<int, GtkWidget*>::iterator iter =
+            radio_groups.find(model->GetGroupIdAt(i));
+
+        if (iter == radio_groups.end()) {
+          menu_item =
+              gtk_radio_menu_item_new_with_mnemonic(NULL, label.c_str());
+          radio_groups[model->GetGroupIdAt(i)] = menu_item;
+        } else {
+          menu_item = gtk_radio_menu_item_new_with_mnemonic_from_widget(
+              GTK_RADIO_MENU_ITEM(iter->second), label.c_str());
+        }
+        break;
+      }
+      case ui::MenuModel::TYPE_BUTTON_ITEM: {
+        NOTIMPLEMENTED();
+        break;
+      }
+      case ui::MenuModel::TYPE_SUBMENU:
+      case ui::MenuModel::TYPE_COMMAND: {
+        if (model->GetIconAt(i, &icon))
+          menu_item = BuildMenuItemWithImage(label, icon);
+        else
+          menu_item = BuildMenuItemWithLabel(label);
+        if (GTK_IS_IMAGE_MENU_ITEM(menu_item)) {
+          SetAlwaysShowImage(menu_item);
+        }
+        break;
+      }
+
+      default:
+        NOTREACHED();
+    }
+
+    if (model->GetTypeAt(i) == ui::MenuModel::TYPE_SUBMENU) {
+      GtkWidget* submenu = gtk_menu_new();
+      ui::MenuModel* submenu_model = model->GetSubmenuModelAt(i);
+      BuildSubmenuFromModel(submenu_model,
+                            submenu,
+                            item_activated_cb,
+                            block_activation,
+                            this_ptr);
+      gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item), submenu);
+
+      // Update all the menu item info in the newly-generated menu.
+      gtk_container_foreach(
+          GTK_CONTAINER(submenu), SetMenuItemInfo, block_activation);
+      submenu_model->MenuWillShow();
+      connect_to_activate = false;
+    }
+
+    ui::Accelerator accelerator;
+    if (model->GetAcceleratorAt(i, &accelerator)) {
+      gtk_widget_add_accelerator(menu_item,
+                                 "activate",
+                                 NULL,
+                                 GetGdkKeyCodeForAccelerator(accelerator),
+                                 GetGdkModifierForAccelerator(accelerator),
+                                 GTK_ACCEL_VISIBLE);
+    }
+
+    g_object_set_data(G_OBJECT(menu_item), "model", model);
+    AppendMenuItemToMenu(i,
+                         model,
+                         menu_item,
+                         menu,
+                         connect_to_activate,
+                         item_activated_cb,
+                         this_ptr);
+
+    menu_item = NULL;
+  }
+}
+
+void SetMenuItemInfo(GtkWidget* widget, void* block_activation_ptr) {
+  if (GTK_IS_SEPARATOR_MENU_ITEM(widget)) {
+    // We need to explicitly handle this case because otherwise we'll ask the
+    // menu delegate about something with an invalid id.
+    return;
+  }
+
+  int id;
+  if (!GetMenuItemID(widget, &id))
+    return;
+
+  ui::MenuModel* model = ModelForMenuItem(GTK_MENU_ITEM(widget));
+  if (!model) {
+    // If we're not providing the sub menu, then there's no model.  For
+    // example, the IME submenu doesn't have a model.
+    return;
+  }
+  bool* block_activation = static_cast<bool*>(block_activation_ptr);
+
+  if (GTK_IS_CHECK_MENU_ITEM(widget)) {
+    GtkCheckMenuItem* item = GTK_CHECK_MENU_ITEM(widget);
+
+    // gtk_check_menu_item_set_active() will send the activate signal. Touching
+    // the underlying "active" property will also call the "activate" handler
+    // for this menu item. So we prevent the "activate" handler from
+    // being called while we set the checkbox.
+    // Why not use one of the glib signal-blocking functions?  Because when we
+    // toggle a radio button, it will deactivate one of the other radio buttons,
+    // which we don't have a pointer to.
+    *block_activation = true;
+    gtk_check_menu_item_set_active(item, model->IsItemCheckedAt(id));
+    *block_activation = false;
+  }
+
+  if (GTK_IS_MENU_ITEM(widget)) {
+    gtk_widget_set_sensitive(widget, model->IsEnabledAt(id));
+
+    if (model->IsVisibleAt(id)) {
+      // Update the menu item label if it is dynamic.
+      if (model->IsItemDynamicAt(id)) {
+        std::string label = ConvertAcceleratorsFromWindowsStyle(
+            UTF16ToUTF8(model->GetLabelAt(id)));
+
+        gtk_menu_item_set_label(GTK_MENU_ITEM(widget), label.c_str());
+        if (GTK_IS_IMAGE_MENU_ITEM(widget)) {
+          gfx::Image icon;
+          if (model->GetIconAt(id, &icon)) {
+            gtk_image_menu_item_set_image(
+                GTK_IMAGE_MENU_ITEM(widget),
+                gtk_image_new_from_pixbuf(
+                    GdkPixbufFromSkBitmap(*icon.ToSkBitmap())));
+          } else {
+            gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(widget), NULL);
+          }
+        }
+      }
+
+      gtk_widget_show(widget);
+    } else {
+      gtk_widget_hide(widget);
+    }
+
+    GtkWidget* submenu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(widget));
+    if (submenu) {
+      gtk_container_foreach(
+          GTK_CONTAINER(submenu), &SetMenuItemInfo, block_activation_ptr);
+    }
+  }
+}
+
+}  // namespace libgtk2ui
diff --git a/chrome/browser/ui/libgtk2ui/menu_util.h b/chrome/browser/ui/libgtk2ui/menu_util.h
new file mode 100644
index 0000000..c81d32d
--- /dev/null
+++ b/chrome/browser/ui/libgtk2ui/menu_util.h
@@ -0,0 +1,56 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_LIBGTK2UI_MENU_UTIL_H_
+#define CHROME_BROWSER_UI_LIBGTK2UI_MENU_UTIL_H_
+
+#include <gtk/gtk.h>
+
+#include "ui/gfx/image/image.h"
+
+namespace ui {
+class MenuModel;
+}
+
+namespace libgtk2ui {
+// Builds GtkImageMenuItems.
+GtkWidget* BuildMenuItemWithImage(const std::string& label, GtkWidget* image);
+GtkWidget* BuildMenuItemWithImage(const std::string& label,
+                                  const gfx::Image& icon);
+GtkWidget* BuildMenuItemWithLabel(const std::string& label);
+
+ui::MenuModel* ModelForMenuItem(GtkMenuItem* menu_item);
+
+// This method is used to build the menu dynamically. The return value is the
+// new menu item.
+GtkWidget* AppendMenuItemToMenu(int index,
+                                ui::MenuModel* model,
+                                GtkWidget* menu_item,
+                                GtkWidget* menu,
+                                bool connect_to_activate,
+                                GCallback item_activated_cb,
+                                void* this_ptr);
+
+// Gets the ID of a menu item.
+// Returns true if the menu item has an ID.
+bool GetMenuItemID(GtkWidget* menu_item, int* menu_id);
+
+// Execute command associated with specified id.
+void ExecuteCommand(ui::MenuModel* model, int id);
+
+// Creates a GtkMenu from |model_|. block_activation_ptr is used to disable
+// the item_activated_callback while we set up the set up the menu items.
+// See comments in definition of SetMenuItemInfo for more info.
+void BuildSubmenuFromModel(ui::MenuModel* model,
+                           GtkWidget* menu,
+                           GCallback item_activated_cb,
+                           bool* block_activation,
+                           void* this_ptr);
+
+// Sets the check mark, enabled/disabled state and dynamic labels on menu items.
+void SetMenuItemInfo(GtkWidget* widget, void* block_activation_ptr);
+
+}  // namespace libgtk2ui
+
+#endif  // CHROME_BROWSER_UI_LIBGTK2UI_MENU_UTIL_H_
diff --git a/chrome/browser/ui/libgtk2ui/skia_utils_gtk2.cc b/chrome/browser/ui/libgtk2ui/skia_utils_gtk2.cc
index 44f03f5..88731b8 100644
--- a/chrome/browser/ui/libgtk2ui/skia_utils_gtk2.cc
+++ b/chrome/browser/ui/libgtk2ui/skia_utils_gtk2.cc
@@ -6,6 +6,11 @@
 
 #include <gdk/gdk.h>
 
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "third_party/skia/include/core/SkUnPreMultiply.h"
+
 namespace libgtk2ui {
 
 const int kSkiaToGDKMultiplier = 257;
@@ -29,4 +34,104 @@
   return gdk_color;
 }
 
+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
+  // recompiling half of our skia extensions with gtk support, which we can't
+  // do in this build.
+  DCHECK_EQ(GDK_COLORSPACE_RGB, gdk_pixbuf_get_colorspace(pixbuf));
+
+  int n_channels = gdk_pixbuf_get_n_channels(pixbuf);
+  int w = gdk_pixbuf_get_width(pixbuf);
+  int h = gdk_pixbuf_get_height(pixbuf);
+
+  SkBitmap ret;
+  ret.setConfig(SkBitmap::kARGB_8888_Config, w, h);
+  ret.allocPixels();
+  ret.eraseColor(0);
+
+  uint32_t* skia_data = static_cast<uint32_t*>(ret.getAddr(0, 0));
+
+  if (n_channels == 4) {
+    int total_length = w * h;
+    guchar* gdk_pixels = gdk_pixbuf_get_pixels(pixbuf);
+
+    // Now here's the trick: we need to convert the gdk data (which is RGBA and
+    // isn't premultiplied) to skia (which can be anything and premultiplied).
+    for (int i = 0; i < total_length; ++i, gdk_pixels += 4) {
+      const unsigned char& red = gdk_pixels[0];
+      const unsigned char& green = gdk_pixels[1];
+      const unsigned char& blue = gdk_pixels[2];
+      const unsigned char& alpha = gdk_pixels[3];
+
+      skia_data[i] = SkPreMultiplyARGB(alpha, red, green, blue);
+    }
+  } else if (n_channels == 3) {
+    // Because GDK makes rowstrides word aligned, we need to do something a bit
+    // more complex when a pixel isn't perfectly a word of memory.
+    int rowstride = gdk_pixbuf_get_rowstride(pixbuf);
+    guchar* gdk_pixels = gdk_pixbuf_get_pixels(pixbuf);
+    for (int y = 0; y < h; ++y) {
+      int row = y * rowstride;
+
+      for (int x = 0; x < w; ++x) {
+        guchar* pixel = gdk_pixels + row + (x * 3);
+        const unsigned char& red = pixel[0];
+        const unsigned char& green = pixel[1];
+        const unsigned char& blue = pixel[2];
+
+        skia_data[y * w + x] = SkPreMultiplyARGB(255, red, green, blue);
+      }
+    }
+  } else {
+    NOTREACHED();
+  }
+
+  return ret;
+}
+
+GdkPixbuf* GdkPixbufFromSkBitmap(const SkBitmap& bitmap) {
+  if (bitmap.isNull())
+    return NULL;
+
+  SkAutoLockPixels lock_pixels(bitmap);
+
+  int width = bitmap.width();
+  int height = bitmap.height();
+
+  GdkPixbuf* pixbuf =
+      gdk_pixbuf_new(GDK_COLORSPACE_RGB,  // The only colorspace gtk supports.
+                     TRUE,                // There is an alpha channel.
+                     8,
+                     width,
+                     height);
+
+  // SkBitmaps are premultiplied, we need to unpremultiply them.
+  const int kBytesPerPixel = 4;
+  uint8* divided = gdk_pixbuf_get_pixels(pixbuf);
+
+  for (int y = 0, i = 0; y < height; y++) {
+    for (int x = 0; x < width; x++) {
+      uint32 pixel = bitmap.getAddr32(0, y)[x];
+
+      int alpha = SkColorGetA(pixel);
+      if (alpha != 0 && alpha != 255) {
+        SkColor unmultiplied = SkUnPreMultiply::PMColorToColor(pixel);
+        divided[i + 0] = SkColorGetR(unmultiplied);
+        divided[i + 1] = SkColorGetG(unmultiplied);
+        divided[i + 2] = SkColorGetB(unmultiplied);
+        divided[i + 3] = alpha;
+      } else {
+        divided[i + 0] = SkColorGetR(pixel);
+        divided[i + 1] = SkColorGetG(pixel);
+        divided[i + 2] = SkColorGetB(pixel);
+        divided[i + 3] = alpha;
+      }
+      i += kBytesPerPixel;
+    }
+  }
+
+  return pixbuf;
+}
+
 }  // namespace libgtk2ui
diff --git a/chrome/browser/ui/libgtk2ui/skia_utils_gtk2.h b/chrome/browser/ui/libgtk2ui/skia_utils_gtk2.h
index 18a1075..1ce81a5 100644
--- a/chrome/browser/ui/libgtk2ui/skia_utils_gtk2.h
+++ b/chrome/browser/ui/libgtk2ui/skia_utils_gtk2.h
@@ -8,6 +8,9 @@
 #include "third_party/skia/include/core/SkColor.h"
 
 typedef struct _GdkColor GdkColor;
+typedef struct _GdkPixbuf GdkPixbuf;
+
+class SkBitmap;
 
 namespace libgtk2ui {
 
@@ -17,6 +20,13 @@
 // Converts ARGB to GdkColor.
 GdkColor SkColorToGdkColor(SkColor color);
 
+const SkBitmap GdkPixbufToImageSkia(GdkPixbuf* pixbuf);
+
+// Convert and copy a SkBitmap to a GdkPixbuf. NOTE: this uses BGRAToRGBA, so
+// it is an expensive operation.  The returned GdkPixbuf will have a refcount of
+// 1, and the caller is responsible for unrefing it when done.
+GdkPixbuf* GdkPixbufFromSkBitmap(const SkBitmap& bitmap);
+
 }  // namespace libgtk2ui
 
 #endif  // CHROME_BROWSER_UI_LIBGTK2UI_SKIA_UTILS_GTK2_H_
diff --git a/chrome/browser/ui/omnibox/action_box_browsertest.cc b/chrome/browser/ui/omnibox/action_box_browsertest.cc
deleted file mode 100644
index 869a641..0000000
--- a/chrome/browser/ui/omnibox/action_box_browsertest.cc
+++ /dev/null
@@ -1,98 +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/command_line.h"
-#include "base/message_loop/message_loop.h"
-#include "base/strings/string16.h"
-#include "base/strings/utf_string_conversions.h"
-#include "chrome/app/chrome_command_ids.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/chrome_notification_types.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_commands.h"
-#include "chrome/browser/ui/browser_tabstrip.h"
-#include "chrome/browser/ui/browser_window.h"
-#include "chrome/browser/ui/omnibox/location_bar.h"
-#include "chrome/browser/ui/toolbar/action_box_menu_model.h"
-#include "chrome/common/chrome_paths.h"
-#include "chrome/common/chrome_switches.h"
-#include "chrome/common/url_constants.h"
-#include "chrome/test/base/in_process_browser_test.h"
-#include "chrome/test/base/interactive_test_utils.h"
-#include "chrome/test/base/testing_profile.h"
-#include "chrome/test/base/ui_test_utils.h"
-#include "content/public/browser/notification_service.h"
-#include "content/public/browser/web_contents.h"
-
-class ActionBoxTest : public InProcessBrowserTest,
-                      public content::NotificationObserver {
- protected:
-  ActionBoxTest() {}
-
-  virtual void SetUpOnMainThread() OVERRIDE {
-    ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
-    ASSERT_NO_FATAL_FAILURE(SetupComponents());
-    chrome::FocusLocationBar(browser());
-    ASSERT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX));
-  }
-
-  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
-    // Enable Action Box UI for the test.
-    command_line->AppendSwitchASCII(switches::kActionBox, "1");
-  }
-
-  void SetupComponents() {}
-
-  virtual void Observe(int type,
-                       const content::NotificationSource& source,
-                       const content::NotificationDetails& details) OVERRIDE {
-    switch (type) {
-      case content::NOTIFICATION_WEB_CONTENTS_DESTROYED:
-      case chrome::NOTIFICATION_TAB_PARENTED:
-      case chrome::NOTIFICATION_AUTOCOMPLETE_CONTROLLER_RESULT_READY:
-      case chrome::NOTIFICATION_HISTORY_LOADED:
-      case chrome::NOTIFICATION_HISTORY_URLS_MODIFIED:
-      case chrome::NOTIFICATION_TEMPLATE_URL_SERVICE_LOADED:
-        break;
-      default:
-        FAIL() << "Unexpected notification type";
-    }
-    base::MessageLoop::current()->Quit();
-  }
-
-  DISALLOW_COPY_AND_ASSIGN(ActionBoxTest);
-};
-
-// Test if Bookmark star appears after bookmarking a page in the action box, and
-// disappears after unbookmarking a page.
-IN_PROC_BROWSER_TEST_F(ActionBoxTest, BookmarkAPageTest) {
-  LocationBarTesting* loc_bar =
-      browser()->window()->GetLocationBar()->GetLocationBarForTesting();
-
-  // Navigate somewhere we can bookmark.
-  ui_test_utils::NavigateToURL(browser(), GURL("http://www.google.com"));
-
-  // Make sure the bookmarking system is up and running.
-  BookmarkModel* model =
-      BookmarkModelFactory::GetForProfile(browser()->profile());
-  ui_test_utils::WaitForBookmarkModelToLoad(model);
-
-  // Page is not bookmarked yet.
-  ASSERT_FALSE(loc_bar->GetBookmarkStarVisibility());
-
-  // Simulate an action box click and menu item selection.
-  chrome::ExecuteCommand(browser(), IDC_BOOKMARK_PAGE_FROM_STAR);
-
-  // Page is now bookmarked.
-  ASSERT_TRUE(loc_bar->GetBookmarkStarVisibility());
-
-  // Get the BookmarkModel to unbookmark the bookmark.
-  bookmark_utils::RemoveAllBookmarks(model, GURL("http://www.google.com"));
-
-  // Page is now unbookmarked.
-  ASSERT_FALSE(loc_bar->GetBookmarkStarVisibility());
-
-}
diff --git a/chrome/browser/ui/omnibox/alternate_nav_infobar_delegate.h b/chrome/browser/ui/omnibox/alternate_nav_infobar_delegate.h
index 5b5f594..90b8fd1 100644
--- a/chrome/browser/ui/omnibox/alternate_nav_infobar_delegate.h
+++ b/chrome/browser/ui/omnibox/alternate_nav_infobar_delegate.h
@@ -12,7 +12,7 @@
 
 class AlternateNavInfoBarDelegate : public InfoBarDelegate {
  public:
-  // Creates an alternate nav delegate and adds it to |infobar_service|.
+  // Creates an alternate nav infobar delegate and adds it to |infobar_service|.
   static void Create(InfoBarService* infobar_service,
                      const GURL& alternate_nav_url);
 
diff --git a/chrome/browser/ui/omnibox/location_bar.h b/chrome/browser/ui/omnibox/location_bar.h
index eeeb843..6a759b1 100644
--- a/chrome/browser/ui/omnibox/location_bar.h
+++ b/chrome/browser/ui/omnibox/location_bar.h
@@ -104,10 +104,6 @@
   // Simulates a left mouse pressed on the visible page action at |index|.
   virtual void TestPageActionPressed(size_t index) = 0;
 
-  // Simulates a left mouse pressed on the action box decoration, followed by
-  // a menu item selection.
-  virtual void TestActionBoxMenuItemSelected(int command_id) = 0;
-
   // Returns whether or not the bookmark star decoration is visible.
   virtual bool GetBookmarkStarVisibility() = 0;
 
diff --git a/chrome/browser/ui/omnibox/omnibox_controller.cc b/chrome/browser/ui/omnibox/omnibox_controller.cc
index 196fef7..b5b7117 100644
--- a/chrome/browser/ui/omnibox/omnibox_controller.cc
+++ b/chrome/browser/ui/omnibox/omnibox_controller.cc
@@ -69,21 +69,6 @@
     const AutocompleteResult::const_iterator match(result.default_match());
     if (match != result.end()) {
       current_match_ = *match;
-      // TODO(beaudoin): This code could be made simpler if AutocompleteMatch
-      // had an |inline_autocompletion| instead of |inline_autocomplete_offset|.
-      // The |fill_into_edit| we get may not match what we have in the view at
-      // that time. We're only interested in the inline_autocomplete part, so
-      // update this here.
-      current_match_.fill_into_edit = omnibox_edit_model_->user_text();
-      if (match->inline_autocomplete_offset < match->fill_into_edit.length()) {
-        current_match_.inline_autocomplete_offset =
-            current_match_.fill_into_edit.length();
-        current_match_.fill_into_edit += match->fill_into_edit.substr(
-            match->inline_autocomplete_offset);
-      } else {
-        current_match_.inline_autocomplete_offset = string16::npos;
-      }
-
       if (!prerender::IsOmniboxEnabled(profile_))
         DoPreconnect(*match);
       omnibox_edit_model_->OnCurrentMatchChanged();
diff --git a/chrome/browser/ui/omnibox/omnibox_current_page_delegate.h b/chrome/browser/ui/omnibox/omnibox_current_page_delegate.h
index faf2135..e91aa2d 100644
--- a/chrome/browser/ui/omnibox/omnibox_current_page_delegate.h
+++ b/chrome/browser/ui/omnibox/omnibox_current_page_delegate.h
@@ -32,6 +32,9 @@
   // Returns the URL of the current page.
   virtual const GURL& GetURL() const = 0;
 
+  // Returns true if the visible entry is a New Tab Page rendered by Instant.
+  virtual bool IsInstantNTP() const = 0;
+
   // Returns whether the current page is loading.
   virtual bool IsLoading() const = 0;
 
diff --git a/chrome/browser/ui/omnibox/omnibox_current_page_delegate_impl.cc b/chrome/browser/ui/omnibox/omnibox_current_page_delegate_impl.cc
index 80d2cdf..7868c8c 100644
--- a/chrome/browser/ui/omnibox/omnibox_current_page_delegate_impl.cc
+++ b/chrome/browser/ui/omnibox/omnibox_current_page_delegate_impl.cc
@@ -10,6 +10,7 @@
 #include "chrome/browser/predictors/autocomplete_action_predictor.h"
 #include "chrome/browser/predictors/autocomplete_action_predictor_factory.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/search/search.h"
 #include "chrome/browser/sessions/session_tab_helper.h"
 #include "chrome/browser/ui/omnibox/omnibox_edit_controller.h"
 #include "chrome/browser/ui/search/search_tab_helper.h"
@@ -35,6 +36,10 @@
   return controller_->GetWebContents()->GetURL();
 }
 
+bool OmniboxCurrentPageDelegateImpl::IsInstantNTP() const {
+  return chrome::IsInstantNTP(controller_->GetWebContents());
+}
+
 bool OmniboxCurrentPageDelegateImpl::IsLoading() const {
   return controller_->GetWebContents()->IsLoading();
 }
@@ -88,6 +93,6 @@
   predictors::AutocompleteActionPredictorFactory::GetForProfile(profile_)->
       StartPrerendering(
           match.destination_url,
-          web_contents->GetController().GetSessionStorageNamespace(),
+          web_contents->GetController().GetSessionStorageNamespaceMap(),
           container_bounds.size());
 }
diff --git a/chrome/browser/ui/omnibox/omnibox_current_page_delegate_impl.h b/chrome/browser/ui/omnibox/omnibox_current_page_delegate_impl.h
index 496f746..9ef4581 100644
--- a/chrome/browser/ui/omnibox/omnibox_current_page_delegate_impl.h
+++ b/chrome/browser/ui/omnibox/omnibox_current_page_delegate_impl.h
@@ -20,6 +20,7 @@
   // OmniboxCurrentPageDelegate.
   virtual bool CurrentPageExists() const OVERRIDE;
   virtual const GURL& GetURL() const OVERRIDE;
+  virtual bool IsInstantNTP() const OVERRIDE;
   virtual bool IsLoading() const OVERRIDE;
   virtual content::NavigationController&
       GetNavigationController() const OVERRIDE;
diff --git a/chrome/browser/ui/omnibox/omnibox_edit_model.cc b/chrome/browser/ui/omnibox/omnibox_edit_model.cc
index 6ba8740..7ade221 100644
--- a/chrome/browser/ui/omnibox/omnibox_edit_model.cc
+++ b/chrome/browser/ui/omnibox/omnibox_edit_model.cc
@@ -347,7 +347,7 @@
 }
 
 bool OmniboxEditModel::CurrentTextIsURL() const {
-  if (view_->toolbar_model()->WouldReplaceSearchURLWithSearchTerms())
+  if (view_->toolbar_model()->WouldReplaceSearchURLWithSearchTerms(false))
     return false;
 
   // If current text is not composed of replaced search terms and
@@ -375,7 +375,7 @@
   // Do not adjust if selection did not start at the beginning of the field, or
   // if the URL was replaced by search terms.
   if ((sel_min != 0) ||
-      view_->toolbar_model()->WouldReplaceSearchURLWithSearchTerms())
+      view_->toolbar_model()->WouldReplaceSearchURLWithSearchTerms(false))
     return;
 
   if (!user_input_in_progress_ && is_all_selected) {
@@ -625,10 +625,9 @@
         autocomplete_controller()->input().type(),
         popup_model()->selected_line(),
         -1,  // don't yet know tab ID; set later if appropriate
-        delegate_->CurrentPageExists() ? ClassifyPage(delegate_->GetURL()) :
-            metrics::OmniboxEventProto_PageClassification_OTHER,
+        ClassifyPage(),
         elapsed_time_since_user_first_modified_omnibox,
-        string16::npos,  // completed_length; possibly set later
+        match.inline_autocompletion.length(),
         elapsed_time_since_last_change_to_default_match,
         result());
 
@@ -646,12 +645,6 @@
 
     if (index != OmniboxPopupModel::kNoMatch)
       log.selected_index = index;
-    if (match.inline_autocomplete_offset != string16::npos) {
-      DCHECK_GE(match.fill_into_edit.length(),
-                match.inline_autocomplete_offset);
-      log.completed_length =
-          match.fill_into_edit.length() - match.inline_autocomplete_offset;
-    }
 
     if ((disposition == CURRENT_TAB) && delegate_->CurrentPageExists()) {
       // If we know the destination is being opened in the current tab,
@@ -702,6 +695,9 @@
         TemplateURLPrepopulateData::kMaxPrepopulatedEngineID);
   }
 
+  // Get the current text before we call RevertAll() which will clear it.
+  string16 current_text = GetViewText();
+
   if (disposition != NEW_BACKGROUND_TAB) {
     base::AutoReset<bool> tmp(&in_revert_, true);
     view_->RevertAll();  // Revert the box to its unedited state
@@ -716,8 +712,8 @@
         GetDestinationURL(match, query_formulation_time);
 
     RecordPercentageMatchHistogram(
-        permanent_text_, match.contents,
-        view_->toolbar_model()->WouldReplaceSearchURLWithSearchTerms(),
+        permanent_text_, current_text,
+        view_->toolbar_model()->WouldReplaceSearchURLWithSearchTerms(false),
         match.transition);
 
     // Track whether the destination URL sends us to a search results page
@@ -726,8 +722,8 @@
         TemplateURLServiceFactory::GetForProfile(profile_)->
             GetDefaultSearchProvider();
     if (default_provider && default_provider->IsSearchURL(destination_url))
-      content::RecordAction(UserMetricsAction(
-          "OmniboxDestinationURLMatchesDefaultSearchProvider"));
+      content::RecordAction(
+          UserMetricsAction("OmniboxDestinationURLIsSearchOnDSP"));
 
     // This calls RevertAll again.
     base::AutoReset<bool> tmp(&in_revert_, true);
@@ -1100,6 +1096,8 @@
            MaybeAcceptKeywordBySpace(user_text_));
 }
 
+// TODO(beaudoin): Merge OnPopupDataChanged with this method once the popup
+// handling has completely migrated to omnibox_controller.
 void OmniboxEditModel::OnCurrentMatchChanged() {
   has_temporary_text_ = false;
 
@@ -1110,17 +1108,12 @@
   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);
+  // OnPopupDataChanged() resets OmniboxController's |current_match_| early
+  // on.  Therefore, copy match.inline_autocompletion to a temp to preserve
+  // its value across the entire call.
+  const string16 inline_autocompletion(match.inline_autocompletion);
+  OnPopupDataChanged(inline_autocompletion, NULL, keyword, is_keyword_hint);
 }
 
 string16 OmniboxEditModel::GetViewText() const {
@@ -1163,7 +1156,7 @@
   DCHECK(match != NULL);
 
   if (!user_input_in_progress_ &&
-      view_->toolbar_model()->WouldReplaceSearchURLWithSearchTerms()) {
+      view_->toolbar_model()->WouldReplaceSearchURLWithSearchTerms(false)) {
     // Any time the user hits enter on the unchanged omnibox, we should reload.
     // When we're not extracting search terms, AcceptInput() will take care of
     // this (see code referring to PAGE_TRANSITION_RELOAD there), but when we're
@@ -1266,17 +1259,26 @@
 }
 
 metrics::OmniboxEventProto::PageClassification
-    OmniboxEditModel::ClassifyPage(const GURL& gurl) const {
+    OmniboxEditModel::ClassifyPage() const {
+  if (!delegate_->CurrentPageExists())
+    return metrics::OmniboxEventProto::OTHER;
+  if (delegate_->IsInstantNTP())
+    return metrics::OmniboxEventProto::INSTANT_NEW_TAB_PAGE;
+  const GURL& gurl = delegate_->GetURL();
   if (!gurl.is_valid())
-    return metrics::OmniboxEventProto_PageClassification_INVALID_SPEC;
+    return metrics::OmniboxEventProto::INVALID_SPEC;
   const std::string& url = gurl.spec();
   if (url == chrome::kChromeUINewTabURL)
-    return metrics::OmniboxEventProto_PageClassification_NEW_TAB_PAGE;
+    return metrics::OmniboxEventProto::NEW_TAB_PAGE;
   if (url == content::kAboutBlankURL)
-    return metrics::OmniboxEventProto_PageClassification_BLANK;
+    return metrics::OmniboxEventProto::BLANK;
   if (url == profile()->GetPrefs()->GetString(prefs::kHomePage))
-    return metrics::OmniboxEventProto_PageClassification_HOMEPAGE;
-  return metrics::OmniboxEventProto_PageClassification_OTHER;
+    return metrics::OmniboxEventProto::HOMEPAGE;
+  if (view_->toolbar_model()->WouldReplaceSearchURLWithSearchTerms(true)) {
+    return metrics::
+        OmniboxEventProto::SEARCH_RESULT_PAGE_DOING_SEARCH_TERM_REPLACEMENT;
+  }
+  return metrics::OmniboxEventProto::OTHER;
 }
 
 void OmniboxEditModel::ClassifyStringForPasteAndGo(
diff --git a/chrome/browser/ui/omnibox/omnibox_edit_model.h b/chrome/browser/ui/omnibox/omnibox_edit_model.h
index 4dff4ef..4087b4d 100644
--- a/chrome/browser/ui/omnibox/omnibox_edit_model.h
+++ b/chrome/browser/ui/omnibox/omnibox_edit_model.h
@@ -299,8 +299,6 @@
   // Access the current view text.
   string16 GetViewText() const;
 
-  string16 user_text() const { return user_text_; }
-
   // TODO(beaudoin): We need this to allow OmniboxController access the
   // InstantController via OmniboxEditController, because the only valid pointer
   // to InstantController is kept in Browser. We should try to get rid of this,
@@ -389,8 +387,7 @@
   // page or a normal web page.  Used for logging omnibox events for
   // UMA opted-in users.  Examines the user's profile to determine if the
   // current page is the user's home page.
-  metrics::OmniboxEventProto::PageClassification ClassifyPage(
-      const GURL& gurl) const;
+  metrics::OmniboxEventProto::PageClassification ClassifyPage() const;
 
   // Sets |match| and |alternate_nav_url| based on classifying |text|.
   // |alternate_nav_url| may be NULL.
diff --git a/chrome/browser/ui/omnibox/omnibox_popup_model.cc b/chrome/browser/ui/omnibox/omnibox_popup_model.cc
index 30d1825..09102d1 100644
--- a/chrome/browser/ui/omnibox/omnibox_popup_model.cc
+++ b/chrome/browser/ui/omnibox/omnibox_popup_model.cc
@@ -16,7 +16,7 @@
 #include "chrome/browser/search_engines/template_url_service_factory.h"
 #include "chrome/browser/ui/omnibox/omnibox_popup_model_observer.h"
 #include "chrome/browser/ui/omnibox/omnibox_popup_view.h"
-#include "third_party/icu/public/common/unicode/ubidi.h"
+#include "third_party/icu/source/common/unicode/ubidi.h"
 #include "ui/gfx/image/image.h"
 #include "ui/gfx/rect.h"
 
@@ -111,13 +111,7 @@
   match.GetKeywordUIState(edit_model_->profile(), &keyword, &is_keyword_hint);
 
   if (reset_to_default) {
-    string16 inline_autocomplete_text;
-    if ((match.inline_autocomplete_offset != string16::npos) &&
-        (match.inline_autocomplete_offset < match.fill_into_edit.length())) {
-      inline_autocomplete_text =
-          match.fill_into_edit.substr(match.inline_autocomplete_offset);
-    }
-    edit_model_->OnPopupDataChanged(inline_autocomplete_text, NULL,
+    edit_model_->OnPopupDataChanged(match.inline_autocompletion, NULL,
                                     keyword, is_keyword_hint);
   } else {
     edit_model_->OnPopupDataChanged(match.fill_into_edit, &current_destination,
diff --git a/chrome/browser/ui/pdf/pdf_tab_helper.cc b/chrome/browser/ui/pdf/pdf_tab_helper.cc
index 3e3bfcb..d78bb81 100644
--- a/chrome/browser/ui/pdf/pdf_tab_helper.cc
+++ b/chrome/browser/ui/pdf/pdf_tab_helper.cc
@@ -4,12 +4,14 @@
 
 #include "chrome/browser/ui/pdf/pdf_tab_helper.h"
 
+#include "chrome/browser/download/download_util.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/omnibox/location_bar.h"
 #include "chrome/browser/ui/pdf/open_pdf_in_reader_prompt_delegate.h"
 #include "chrome/browser/ui/pdf/pdf_unsupported_feature.h"
+#include "chrome/browser/ui/tab_contents/core_tab_helper.h"
 #include "chrome/common/render_messages.h"
 #include "content/public/browser/navigation_details.h"
 
@@ -32,7 +34,10 @@
   bool handled = true;
   IPC_BEGIN_MESSAGE_MAP(PDFTabHelper, message)
     IPC_MESSAGE_HANDLER(ChromeViewHostMsg_PDFHasUnsupportedFeature,
-                        OnPDFHasUnsupportedFeature)
+                        OnHasUnsupportedFeature)
+    IPC_MESSAGE_HANDLER(ChromeViewHostMsg_PDFSaveURLAs, OnSaveURLAs)
+    IPC_MESSAGE_HANDLER(ChromeViewHostMsg_PDFUpdateContentRestrictions,
+                        OnUpdateContentRestrictions)
     IPC_MESSAGE_UNHANDLED(handled = false)
   IPC_END_MESSAGE_MAP()
   return handled;
@@ -64,6 +69,18 @@
   location_bar->UpdateOpenPDFInReaderPrompt();
 }
 
-void PDFTabHelper::OnPDFHasUnsupportedFeature() {
+void PDFTabHelper::OnHasUnsupportedFeature() {
   PDFHasUnsupportedFeature(web_contents());
 }
+
+void PDFTabHelper::OnSaveURLAs(const GURL& url,
+                               const content::Referrer& referrer) {
+  download_util::RecordDownloadSource(download_util::INITIATED_BY_PDF_SAVE);
+  web_contents()->SaveFrame(url, referrer);
+}
+
+void PDFTabHelper::OnUpdateContentRestrictions(int content_restrictions) {
+  CoreTabHelper* core_tab_helper =
+      CoreTabHelper::FromWebContents(web_contents());
+  core_tab_helper->UpdateContentRestrictions(content_restrictions);
+}
diff --git a/chrome/browser/ui/pdf/pdf_tab_helper.h b/chrome/browser/ui/pdf/pdf_tab_helper.h
index d50c86f..978c605 100644
--- a/chrome/browser/ui/pdf/pdf_tab_helper.h
+++ b/chrome/browser/ui/pdf/pdf_tab_helper.h
@@ -41,7 +41,10 @@
   void UpdateLocationBar();
 
   // Message handlers.
-  void OnPDFHasUnsupportedFeature();
+  void OnHasUnsupportedFeature();
+  void OnSaveURLAs(const GURL& url,
+                   const content::Referrer& referrer);
+  void OnUpdateContentRestrictions(int content_restrictions);
 
   // The model for the confirmation prompt to open a PDF in Adobe Reader.
   scoped_ptr<OpenPDFInReaderPromptDelegate> open_in_reader_prompt_;
diff --git a/chrome/browser/ui/pdf/pdf_unsupported_feature.cc b/chrome/browser/ui/pdf/pdf_unsupported_feature.cc
index d6c9638..fde1364 100644
--- a/chrome/browser/ui/pdf/pdf_unsupported_feature.cc
+++ b/chrome/browser/ui/pdf/pdf_unsupported_feature.cc
@@ -50,7 +50,7 @@
 using content::Referrer;
 using content::UserMetricsAction;
 using content::WebContents;
-using webkit::WebPluginInfo;
+using content::WebPluginInfo;
 
 namespace {
 
@@ -243,7 +243,7 @@
  public:
   // |reader| is NULL if Adobe Reader isn't installed.
   PDFUnsupportedFeaturePromptDelegate(WebContents* web_contents,
-                                      const webkit::WebPluginInfo* reader,
+                                      const content::WebPluginInfo* reader,
                                       PluginFinder* plugin_finder);
   virtual ~PDFUnsupportedFeaturePromptDelegate();
 
@@ -267,7 +267,7 @@
 
 PDFUnsupportedFeaturePromptDelegate::PDFUnsupportedFeaturePromptDelegate(
     WebContents* web_contents,
-    const webkit::WebPluginInfo* reader,
+    const content::WebPluginInfo* reader,
     PluginFinder* plugin_finder)
     : web_contents_(web_contents),
       reader_installed_(!!reader),
@@ -358,13 +358,13 @@
 #if defined(OS_WIN) && defined(ENABLE_PLUGIN_INSTALLATION)
 void GotPluginsCallback(int process_id,
                         int routing_id,
-                        const std::vector<webkit::WebPluginInfo>& plugins) {
+                        const std::vector<content::WebPluginInfo>& plugins) {
   WebContents* web_contents =
       tab_util::GetWebContentsByID(process_id, routing_id);
   if (!web_contents)
     return;
 
-  const webkit::WebPluginInfo* reader = NULL;
+  const content::WebPluginInfo* reader = NULL;
   PluginFinder* plugin_finder = PluginFinder::GetInstance();
   for (size_t i = 0; i < plugins.size(); ++i) {
     scoped_ptr<PluginMetadata> plugin_metadata(
diff --git a/chrome/browser/ui/prefs/prefs_tab_helper.cc b/chrome/browser/ui/prefs/prefs_tab_helper.cc
index 30feabb..3e3f718 100644
--- a/chrome/browser/ui/prefs/prefs_tab_helper.cc
+++ b/chrome/browser/ui/prefs/prefs_tab_helper.cc
@@ -25,8 +25,8 @@
 #include "content/public/browser/web_contents.h"
 #include "grit/locale_settings.h"
 #include "grit/platform_locale_settings.h"
-#include "third_party/icu/public/common/unicode/uchar.h"
-#include "third_party/icu/public/common/unicode/uscript.h"
+#include "third_party/icu/source/common/unicode/uchar.h"
+#include "third_party/icu/source/common/unicode/uscript.h"
 #include "webkit/common/webpreferences.h"
 
 #if defined(OS_POSIX) && !defined(OS_MACOSX) && defined(ENABLE_THEMES)
diff --git a/chrome/browser/ui/search/instant_controller.cc b/chrome/browser/ui/search/instant_controller.cc
index 6203445..28ce7fa 100644
--- a/chrome/browser/ui/search/instant_controller.cc
+++ b/chrome/browser/ui/search/instant_controller.cc
@@ -19,7 +19,6 @@
 #include "chrome/browser/search_engines/template_url_service.h"
 #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_tab.h"
 #include "chrome/browser/ui/search/search_tab_helper.h"
 #include "chrome/common/chrome_switches.h"
@@ -102,16 +101,6 @@
   SearchTabHelper::FromWebContents(contents)->NavigationEntryUpdated();
 }
 
-template <typename T>
-void DeletePageSoon(scoped_ptr<T> page) {
-  if (page->contents()) {
-    base::MessageLoop::current()->DeleteSoon(
-        FROM_HERE, page->ReleaseContents().release());
-  }
-
-  base::MessageLoop::current()->DeleteSoon(FROM_HERE, page.release());
-}
-
 }  // namespace
 
 InstantController::InstantController(BrowserInstantController* browser,
@@ -121,41 +110,9 @@
       omnibox_focus_state_(OMNIBOX_FOCUS_NONE),
       omnibox_focus_change_reason_(OMNIBOX_FOCUS_CHANGE_EXPLICIT),
       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_) {
-    InstantService* instant_service = GetInstantService();
-    instant_service->AddObserver(this);
-  }
 }
 
 InstantController::~InstantController() {
-  if (browser_) {
-    InstantService* instant_service = GetInstantService();
-    instant_service->RemoveObserver(this);
-  }
-}
-
-scoped_ptr<content::WebContents> InstantController::ReleaseNTPContents() {
-  if (!extended_enabled() || !browser_->profile() ||
-      browser_->profile()->IsOffTheRecord() ||
-      !chrome::ShouldShowInstantNTP())
-    return scoped_ptr<content::WebContents>();
-
-  LOG_INSTANT_DEBUG_EVENT(this, "ReleaseNTPContents");
-
-  if (ShouldSwitchToLocalNTP())
-    ResetNTP(GetLocalInstantURL());
-
-  scoped_ptr<content::WebContents> ntp_contents = ntp_->ReleaseContents();
-
-  // Preload a new Instant NTP.
-  ResetNTP(GetInstantURL());
-
-  return ntp_contents.Pass();
 }
 
 void InstantController::SetOmniboxBounds(const gfx::Rect& bounds) {
@@ -163,19 +120,10 @@
     return;
 
   omnibox_bounds_ = bounds;
-  if (ntp_)
-    ntp_->sender()->SetOmniboxBounds(omnibox_bounds_);
   if (instant_tab_)
     instant_tab_->sender()->SetOmniboxBounds(omnibox_bounds_);
 }
 
-void InstantController::OnDefaultSearchProviderChanged() {
-  if (ntp_ && extended_enabled()) {
-    ntp_.reset();
-    ResetNTP(GetInstantURL());
-  }
-}
-
 void InstantController::ToggleVoiceSearch() {
   if (instant_tab_)
     instant_tab_->sender()->ToggleVoiceSearch();
@@ -190,36 +138,26 @@
     return;
   }
 
-  if (IsContentsFrom(instant_tab(), contents)) {
-    // Verify we're not already on a local page and that the URL precisely
-    // equals the instant_url (minus the query params, as those will be filled
-    // in by template values).  This check is necessary to make sure we don't
-    // inadvertently redirect to the local NTP if someone, say, reloads a SRP
-    // while offline, as a committed results page still counts as an instant
-    // url.  We also check to make sure there's no forward history, as if
-    // someone hits the back button a lot when offline and returns to a NTP
-    // we don't want to redirect and nuke their forward history stack.
-    const GURL& current_url = contents->GetURL();
-    if (instant_tab_->IsLocal() ||
-        !chrome::MatchesOriginAndPath(GURL(GetInstantURL()), current_url) ||
-        !current_url.ref().empty() ||
-        contents->GetController().CanGoForward())
-      return;
-    LOG_INSTANT_DEBUG_EVENT(this, "InstantPageLoadFailed: instant_tab");
-    RedirectToLocalNTP(contents);
-  } else if (IsContentsFrom(ntp(), contents)) {
-    LOG_INSTANT_DEBUG_EVENT(this, "InstantPageLoadFailed: ntp");
-    bool is_local = ntp_->IsLocal();
-    DeletePageSoon(ntp_.Pass());
-    if (!is_local)
-      ResetNTP(GetLocalInstantURL());
-  } else {
-    NOTREACHED();
-  }
-}
+  DCHECK(IsContentsFrom(instant_tab(), contents));
 
-content::WebContents* InstantController::GetNTPContents() const {
-  return ntp_ ? ntp_->contents() : NULL;
+  // Verify we're not already on a local page and that the URL precisely
+  // equals the instant_url (minus the query params, as those will be filled
+  // in by template values).  This check is necessary to make sure we don't
+  // inadvertently redirect to the local NTP if someone, say, reloads a SRP
+  // while offline, as a committed results page still counts as an instant
+  // url.  We also check to make sure there's no forward history, as if
+  // someone hits the back button a lot when offline and returns to a NTP
+  // we don't want to redirect and nuke their forward history stack.
+  const GURL& current_url = contents->GetURL();
+  GURL instant_url = chrome::GetInstantURL(profile(),
+                                           chrome::kDisableStartMargin);
+  if (instant_tab_->IsLocal() ||
+      !chrome::MatchesOriginAndPath(instant_url, current_url) ||
+      !current_url.ref().empty() ||
+      contents->GetController().CanGoForward())
+    return;
+  LOG_INSTANT_DEBUG_EVENT(this, "InstantPageLoadFailed: instant_tab");
+  RedirectToLocalNTP(contents);
 }
 
 bool InstantController::SubmitQuery(const string16& search_terms) {
@@ -291,17 +229,6 @@
     InstantTab::EmitMouseoverCount(contents);
 }
 
-void InstantController::ThemeInfoChanged(
-    const ThemeBackgroundInfo& theme_info) {
-  if (!extended_enabled())
-    return;
-
-  if (ntp_)
-    ntp_->sender()->SendThemeBackgroundInfo(theme_info);
-  if (instant_tab_)
-    instant_tab_->sender()->SendThemeBackgroundInfo(theme_info);
-}
-
 void InstantController::LogDebugEvent(const std::string& info) const {
   DVLOG(1) << info;
 
@@ -316,19 +243,6 @@
   debug_events_.clear();
 }
 
-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,
-      content::Source<InstantController>(this),
-      content::NotificationService::NoDetails());
-}
-
 void InstantController::DeleteMostVisitedItem(const GURL& url) {
   DCHECK(!url.is_empty());
   InstantService* instant_service = GetInstantService();
@@ -363,45 +277,6 @@
   return instant_tab_.get();
 }
 
-InstantNTP* InstantController::ntp() const {
-  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(
-    const content::WebContents* contents) {
-  if (!extended_enabled())
-    return;
-
-  // Update theme info so that the page picks it up.
-  InstantService* instant_service = GetInstantService();
-  if (instant_service) {
-    instant_service->UpdateThemeInfo();
-    instant_service->UpdateMostVisitedItemsInfo();
-  }
-
-  // Ensure the searchbox API has the correct initial state.
-  if (IsContentsFrom(ntp(), contents)) {
-    ntp_->sender()->SetOmniboxBounds(omnibox_bounds_);
-    ntp_->InitializeFonts();
-    ntp_->InitializePromos();
-  } else {
-    NOTREACHED();
-  }
-}
-
 void InstantController::InstantSupportChanged(
     InstantSupportState instant_support) {
   // Handle INSTANT_SUPPORT_YES here because InstantPage is not hooked up to the
@@ -416,53 +291,25 @@
 void InstantController::InstantSupportDetermined(
     const content::WebContents* contents,
     bool supports_instant) {
-  if (IsContentsFrom(instant_tab(), contents)) {
-    if (!supports_instant)
-      base::MessageLoop::current()->DeleteSoon(FROM_HERE,
-                                               instant_tab_.release());
+  DCHECK(IsContentsFrom(instant_tab(), contents));
 
-    content::NotificationService::current()->Notify(
-        chrome::NOTIFICATION_INSTANT_TAB_SUPPORT_DETERMINED,
-        content::Source<InstantController>(this),
-        content::NotificationService::NoDetails());
-  } else if (IsContentsFrom(ntp(), contents)) {
-    if (!supports_instant) {
-      bool is_local = ntp_->IsLocal();
-      DeletePageSoon(ntp_.Pass());
-      // Preload a local NTP in place of the broken online one.
-      if (!is_local)
-        ResetNTP(GetLocalInstantURL());
-    }
+  if (!supports_instant)
+    base::MessageLoop::current()->DeleteSoon(FROM_HERE, instant_tab_.release());
 
-    content::NotificationService::current()->Notify(
-        chrome::NOTIFICATION_INSTANT_NTP_SUPPORT_DETERMINED,
-        content::Source<InstantController>(this),
-        content::NotificationService::NoDetails());
-
-  } else {
-    NOTREACHED();
-  }
-}
-
-void InstantController::InstantPageRenderProcessGone(
-    const content::WebContents* contents) {
-  if (IsContentsFrom(ntp(), contents)) {
-    DeletePageSoon(ntp_.Pass());
-  } else {
-    NOTREACHED();
-  }
+  content::NotificationService::current()->Notify(
+      chrome::NOTIFICATION_INSTANT_TAB_SUPPORT_DETERMINED,
+      content::Source<InstantController>(this),
+      content::NotificationService::NoDetails());
 }
 
 void InstantController::InstantPageAboutToNavigateMainFrame(
     const content::WebContents* contents,
     const GURL& url) {
-  if (IsContentsFrom(instant_tab(), contents)) {
-    // The Instant tab navigated.  Send it the data it needs to display
-    // properly.
-    UpdateInfoForInstantTab();
-  } else {
-    NOTREACHED();
-  }
+  DCHECK(IsContentsFrom(instant_tab(), contents));
+
+  // The Instant tab navigated.  Send it the data it needs to display
+  // properly.
+  UpdateInfoForInstantTab();
 }
 
 void InstantController::FocusOmnibox(const content::WebContents* contents,
@@ -518,88 +365,15 @@
   browser_->OpenURL(url, transition, disposition);
 }
 
-std::string InstantController::GetLocalInstantURL() const {
-  return chrome::GetLocalInstantURL(profile()).spec();
-}
-
-std::string InstantController::GetInstantURL() const {
-  if (extended_enabled() && net::NetworkChangeNotifier::IsOffline())
-    return GetLocalInstantURL();
-
-  const GURL instant_url = chrome::GetInstantURL(profile(),
-                                                 omnibox_bounds_.x());
-  if (instant_url.is_valid())
-    return instant_url.spec();
-
-  // Only extended mode has a local fallback.
-  return extended_enabled() ? GetLocalInstantURL() : std::string();
-}
-
 bool InstantController::extended_enabled() const {
   return extended_enabled_;
 }
 
-bool InstantController::PageIsCurrent(const InstantPage* page) const {
-
-  const std::string& instant_url = GetInstantURL();
-  if (instant_url.empty() ||
-      !chrome::MatchesOriginAndPath(GURL(page->instant_url()),
-                                    GURL(instant_url)))
-    return false;
-
-  return page->supports_instant();
-}
-
-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,
-                            browser_->profile()->IsOffTheRecord()));
-  ntp_->InitContents(profile(), browser_->GetActiveWebContents(),
-                     base::Bind(&InstantController::ReloadStaleNTP,
-                                base::Unretained(this)));
-  LOG_INSTANT_DEBUG_EVENT(this, base::StringPrintf(
-      "ResetNTP: instant_url='%s'", instant_url.c_str()));
-}
-
-void InstantController::ReloadStaleNTP() {
-  if (extended_enabled())
-    ResetNTP(GetInstantURL());
-}
-
-bool InstantController::ShouldSwitchToLocalNTP() const {
-  if (!ntp())
-    return true;
-
-  // Assume users with Javascript disabled do not want the online experience.
-  if (!IsJavascriptEnabled())
-    return true;
-
-  // Already a local page. Not calling IsLocal() because we want to distinguish
-  // between the Google-specific and generic local NTP.
-  if (extended_enabled() && ntp()->instant_url() == GetLocalInstantURL())
-    return false;
-
-  if (PageIsCurrent(ntp()))
-    return false;
-
-  // The preloaded NTP does not support instant yet. If we're not in startup,
-  // always fall back to the local NTP. If we are in startup, use the local NTP
-  // (unless the finch flag to use the remote NTP is set).
-  return !(InStartup() && chrome::ShouldPreferRemoteNTPOnStartup());
-}
-
 void InstantController::ResetInstantTab() {
   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, browser_->profile()->IsOffTheRecord()));
+      instant_tab_.reset(new InstantTab(this, browser_->profile()));
       instant_tab_->Init(active_tab);
       UpdateInfoForInstantTab();
     }
@@ -638,39 +412,15 @@
 
 void InstantController::RedirectToLocalNTP(content::WebContents* contents) {
   contents->GetController().LoadURL(
-    chrome::GetLocalInstantURL(browser_->profile()),
-    content::Referrer(),
-    content::PAGE_TRANSITION_SERVER_REDIRECT,
-    std::string());  // No extra headers.
+      GURL(chrome::kChromeSearchLocalNtpUrl),
+      content::Referrer(),
+      content::PAGE_TRANSITION_SERVER_REDIRECT,
+      std::string());  // No extra headers.
   // TODO(dcblack): Remove extraneous history entry caused by 404s.
   // Note that the base case of a 204 being returned doesn't push a history
   // entry.
 }
 
-bool InstantController::IsJavascriptEnabled() const {
-  GURL instant_url(GetInstantURL());
-  GURL origin(instant_url.GetOrigin());
-  ContentSetting js_setting = profile()->GetHostContentSettingsMap()->
-      GetContentSetting(origin, origin, CONTENT_SETTINGS_TYPE_JAVASCRIPT,
-                        NO_RESOURCE_IDENTIFIER);
-  // Javascript can be disabled either in content settings or via a WebKit
-  // preference, so check both. Disabling it through the Settings page affects
-  // content settings. I'm not sure how to disable the WebKit preference, but
-  // it's theoretically possible some users have it off.
-  bool js_content_enabled =
-      js_setting == CONTENT_SETTING_DEFAULT ||
-      js_setting == CONTENT_SETTING_ALLOW;
-  bool js_webkit_enabled = profile()->GetPrefs()->GetBoolean(
-      prefs::kWebKitJavascriptEnabled);
-  return js_content_enabled && js_webkit_enabled;
-}
-
-bool InstantController::InStartup() const {
-  // TODO(shishir): This is not completely reliable. Find a better way to detect
-  // 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 7964d87..b204ba0 100644
--- a/chrome/browser/ui/search/instant_controller.h
+++ b/chrome/browser/ui/search/instant_controller.h
@@ -14,20 +14,17 @@
 #include "base/gtest_prod_util.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/strings/string16.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 "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"
 #include "url/gurl.h"
 
 class BrowserInstantController;
-class InstantNTP;
 class InstantService;
 class InstantTab;
 class Profile;
@@ -43,49 +40,29 @@
 // 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 two
-// instances of InstantPage:
-//  (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.
-//  (2) An InstantTab instance which points to the currently active tab, if it
-//      supports the Embedded Search API.
-//
-// Both are backed by a WebContents. InstantNTP owns its WebContents and
-// InstantTab does not.
+// In extended mode, InstantController maintains and coordinates an InstantTab
+// instance of InstantPage. An InstantTab instance points to the currently
+// active tab, if it supports the Embedded Search API. InstantTab is backed by a
+// WebContents and it does not own that WebContents.
 //
 // InstantController is owned by Browser via BrowserInstantController.
-class InstantController : public InstantPage::Delegate,
-                          public InstantServiceObserver {
+class InstantController : public InstantPage::Delegate {
  public:
   InstantController(BrowserInstantController* browser,
                     bool extended_enabled);
   virtual ~InstantController();
 
-  // 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 stored start-edge margin and width of the omnibox.
   void SetOmniboxBounds(const gfx::Rect& bounds);
 
-  // Called when the default search provider changes. Resets InstantNTP.
-  void OnDefaultSearchProviderChanged();
-
   // Notifies |instant_Tab_| to toggle voice search.
   void ToggleVoiceSearch();
 
-  // The ntp WebContents. May be NULL. InstantController retains ownership.
-  content::WebContents* GetNTPContents() 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 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
   // the view gaining focus.
@@ -112,16 +89,6 @@
   // Resets list of debug events.
   void ClearDebugEvents();
 
-  // 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 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).
-  virtual std::string GetInstantURL() const;
-
   // See comments for |debug_events_| below.
   const std::list<std::pair<int64, std::string> >& debug_events() {
     return debug_events_;
@@ -136,31 +103,13 @@
   virtual bool extended_enabled() const;
 
   virtual InstantTab* instant_tab() const;
-  virtual InstantNTP* ntp() const;
 
   virtual Profile* profile() const;
 
-  // Returns true if Javascript is enabled and false otherwise.
-  virtual bool IsJavascriptEnabled() const;
-
-  // Returns true if the browser is in startup.
-  virtual bool InStartup() const;
-
  private:
   friend class InstantExtendedManualTest;
   friend class InstantTestBase;
-#define UNIT_F(test) FRIEND_TEST_ALL_PREFIXES(InstantControllerTest, test)
-  UNIT_F(DoesNotSwitchToLocalNTPIfOnCurrentNTP);
-  UNIT_F(DoesNotSwitchToLocalNTPIfOnLocalNTP);
-  UNIT_F(IsJavascriptEnabled);
-  UNIT_F(IsJavascriptEnabledChecksContentSettings);
-  UNIT_F(IsJavascriptEnabledChecksPrefs);
-  UNIT_F(PrefersRemoteNTPOnStartup);
-  UNIT_F(SwitchesToLocalNTPIfJSDisabled);
-  UNIT_F(SwitchesToLocalNTPIfNoInstantSupport);
-  UNIT_F(SwitchesToLocalNTPIfNoNTPReady);
-  UNIT_F(SwitchesToLocalNTPIfPathBad);
-#undef UNIT_F
+
   FRIEND_TEST_ALL_PREFIXES(InstantExtendedTest, ExtendedModeIsOn);
   FRIEND_TEST_ALL_PREFIXES(InstantExtendedTest, MostVisited);
   FRIEND_TEST_ALL_PREFIXES(InstantExtendedTest, NTPIsPreloaded);
@@ -195,13 +144,9 @@
   // Overridden from InstantPage::Delegate:
   // TODO(shishir): We assume that the WebContent's current RenderViewHost is
   // the RenderViewHost being created which is not always true. Fix this.
-  virtual void InstantPageRenderViewCreated(
-      const content::WebContents* contents) OVERRIDE;
   virtual void InstantSupportDetermined(
       const content::WebContents* contents,
       bool supports_instant) OVERRIDE;
-  virtual void InstantPageRenderProcessGone(
-      const content::WebContents* contents) OVERRIDE;
   virtual void InstantPageAboutToNavigateMainFrame(
       const content::WebContents* contents,
       const GURL& url) OVERRIDE;
@@ -215,11 +160,6 @@
       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;
@@ -239,20 +179,6 @@
   // Helper for OmniboxFocusChanged. Commit or discard the overlay.
   void OmniboxLostFocus(gfx::NativeView view_gaining_focus);
 
-  // Returns the local Instant URL. (Just a convenience wrapper around
-  // chrome::GetLocalInstantURL.)
-  virtual std::string GetLocalInstantURL() const;
-
-  // Returns true if |page| has an up-to-date Instant URL and supports Instant.
-  // Note that local URLs will not pass this check.
-  bool PageIsCurrent(const InstantPage* page) const;
-
-  // Recreates |ntp_| using |instant_url|.
-  void ResetNTP(const std::string& instant_url);
-
-  // Returns true if we should switch to using the local NTP.
-  bool ShouldSwitchToLocalNTP() 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();
@@ -276,8 +202,7 @@
   // Instant is effectively disabled.
   const bool extended_enabled_;
 
-  // The instances of InstantPage maintained by InstantController.
-  scoped_ptr<InstantNTP> ntp_;
+  // The instance of InstantPage maintained by InstantController.
   scoped_ptr<InstantTab> instant_tab_;
 
   // Omnibox focus state.
diff --git a/chrome/browser/ui/search/instant_controller_unittest.cc b/chrome/browser/ui/search/instant_controller_unittest.cc
deleted file mode 100644
index b96540b..0000000
--- a/chrome/browser/ui/search/instant_controller_unittest.cc
+++ /dev/null
@@ -1,289 +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/memory/scoped_ptr.h"
-#include "base/metrics/histogram.h"
-#include "base/metrics/histogram_samples.h"
-#include "base/metrics/statistics_recorder.h"
-#include "base/prefs/pref_service.h"
-#include "chrome/browser/content_settings/host_content_settings_map.h"
-#include "chrome/browser/search/search.h"
-#include "chrome/browser/ui/search/instant_controller.h"
-#include "chrome/browser/ui/search/instant_ntp.h"
-#include "chrome/common/content_settings.h"
-#include "chrome/common/pref_names.h"
-#include "chrome/test/base/testing_profile.h"
-#include "content/public/test/test_browser_thread.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using base::HistogramBase;
-using base::HistogramSamples;
-using base::StatisticsRecorder;
-
-class TestableInstantNTP : public InstantNTP {
- public:
-  TestableInstantNTP(InstantController* controller,
-                     const std::string& instant_url)
-      : InstantNTP(controller, instant_url, false) {
-  }
-
-  // Overrides from InstantPage
-  virtual bool supports_instant() const OVERRIDE {
-    return test_supports_instant_;
-  }
-
-  virtual bool IsLocal() const OVERRIDE {
-    return test_is_local_;
-  };
-
-  virtual const std::string& instant_url() const OVERRIDE {
-    return test_instant_url_;
-  }
-
-  void set_instant_url(const std::string& instant_url) {
-    test_instant_url_ = instant_url;
-  }
-
-  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 TestableInstantController : public InstantController {
- public:
-  TestableInstantController()
-      : InstantController(NULL, true),
-        test_instant_url_("http://test_url"),
-        test_extended_enabled_(true),
-        override_javascript_enabled_(true),
-        test_javascript_enabled_(true),
-        test_in_startup_(false),
-        test_ntp_(NULL) {}
-
-  // Overrides from InstantController
-  virtual std::string GetInstantURL() const OVERRIDE {
-    return test_instant_url_;
-  }
-
-  virtual std::string GetLocalInstantURL() const OVERRIDE {
-    return "http://local_instant_url";
-  }
-
-  virtual bool extended_enabled() const OVERRIDE {
-    return test_extended_enabled_;
-  }
-
-  virtual InstantNTP* ntp() const OVERRIDE {
-    return test_ntp_;
-  }
-
-  void set_instant_url(std::string instant_url) {
-    test_instant_url_ = instant_url;
-  }
-
-  void set_extended_enabled(bool extended_enabled) {
-    test_extended_enabled_ = extended_enabled;
-  }
-
-  void set_ntp(InstantNTP* ntp) {
-    test_ntp_ = ntp;
-  }
-
-  void set_javascript_enabled(bool javascript_enabled) {
-    override_javascript_enabled_ = true;
-    test_javascript_enabled_ = javascript_enabled;
-  }
-
-  void set_override_javascript_enabled(bool override_javascript_enabled) {
-    override_javascript_enabled_ = override_javascript_enabled;
-  }
-
-  void set_in_startup(bool in_startup) {
-    test_in_startup_ = in_startup;
-  }
-
-  virtual bool IsJavascriptEnabled() const OVERRIDE {
-    if (override_javascript_enabled_)
-      return test_javascript_enabled_;
-    else
-      return InstantController::IsJavascriptEnabled();
-  }
-
-  virtual bool InStartup() const OVERRIDE {
-    return test_in_startup_;
-  }
-
-  virtual Profile* profile() const OVERRIDE {
-    return &profile_;
-  }
-
-private:
-  std::string test_instant_url_;
-  bool test_extended_enabled_;
-  bool override_javascript_enabled_;
-  bool test_javascript_enabled_;
-  bool test_in_startup_;
-  InstantNTP* test_ntp_;
-  mutable TestingProfile profile_;
-};
-
-class InstantControllerTest : public testing::Test {
- public:
-  InstantControllerTest()
-      : ui_thread_(content::BrowserThread::UI),
-        instant_controller_(new TestableInstantController()) {
-  }
-
-  virtual void SetUp() OVERRIDE {
-    base::StatisticsRecorder::Initialize();
-  }
-
-  TestableInstantController* instant_controller() {
-    return instant_controller_.get();
-  }
-
- private:
-  content::TestBrowserThread ui_thread_;
-  scoped_ptr<TestableInstantController> instant_controller_;
-};
-
-TEST_F(InstantControllerTest, PrefersRemoteNTPOnStartup) {
-  std::string instant_url("http://instant_url");
-  scoped_ptr<TestableInstantNTP> ntp(new TestableInstantNTP(
-      instant_controller(), instant_url));
-  ntp->set_is_local(false);
-  instant_controller()->set_ntp(ntp.get());
-  instant_controller()->set_javascript_enabled(true);
-  instant_controller()->set_extended_enabled(true);
-  instant_controller()->set_instant_url(instant_url);
-  ntp->set_instant_url(instant_url);
-  ntp->set_supports_instant(false);
-  instant_controller()->set_in_startup(true);
-  EXPECT_EQ(!chrome::ShouldPreferRemoteNTPOnStartup(),
-            instant_controller()->ShouldSwitchToLocalNTP());
-}
-
-TEST_F(InstantControllerTest, SwitchesToLocalNTPIfNoInstantSupport) {
-  std::string instant_url("http://instant_url");
-  scoped_ptr<TestableInstantNTP> ntp(new TestableInstantNTP(
-      instant_controller(), instant_url));
-  ntp.reset(new TestableInstantNTP(instant_controller(), instant_url));
-  ntp->set_is_local(false);
-  instant_controller()->set_ntp(ntp.get());
-  instant_controller()->set_javascript_enabled(true);
-  instant_controller()->set_extended_enabled(true);
-  instant_controller()->set_instant_url(instant_url);
-  ntp->set_instant_url(instant_url);
-  ntp->set_supports_instant(false);
-  instant_controller()->set_in_startup(false);
-  EXPECT_TRUE(instant_controller()->ShouldSwitchToLocalNTP());
-}
-
-TEST_F(InstantControllerTest, SwitchesToLocalNTPIfPathBad) {
-  std::string instant_url("http://instant_url");
-  scoped_ptr<TestableInstantNTP> ntp(new TestableInstantNTP(
-      instant_controller(), instant_url));
-  ntp.reset(new TestableInstantNTP(instant_controller(), instant_url));
-  ntp->set_is_local(false);
-  instant_controller()->set_ntp(ntp.get());
-  instant_controller()->set_javascript_enabled(true);
-  instant_controller()->set_extended_enabled(true);
-  instant_controller()->set_instant_url("http://bogus_url");
-  ntp->set_instant_url(instant_url);
-  ntp->set_supports_instant(true);
-  instant_controller()->set_in_startup(false);
-  EXPECT_TRUE(instant_controller()->ShouldSwitchToLocalNTP());
-}
-
-TEST_F(InstantControllerTest, DoesNotSwitchToLocalNTPIfOnCurrentNTP) {
-  std::string instant_url("http://instant_url");
-  scoped_ptr<TestableInstantNTP> ntp(new TestableInstantNTP(
-      instant_controller(), instant_url));
-  ntp.reset(new TestableInstantNTP(instant_controller(), instant_url));
-  ntp->set_is_local(false);
-  instant_controller()->set_ntp(ntp.get());
-  instant_controller()->set_javascript_enabled(true);
-  instant_controller()->set_extended_enabled(true);
-  instant_controller()->set_instant_url(instant_url);
-  ntp->set_instant_url(instant_url);
-  ntp->set_supports_instant(true);
-  instant_controller()->set_in_startup(false);
-  EXPECT_FALSE(instant_controller()->ShouldSwitchToLocalNTP());
-}
-
-TEST_F(InstantControllerTest, DoesNotSwitchToLocalNTPIfOnLocalNTP) {
-  std::string instant_url("http://instant_url");
-  scoped_ptr<TestableInstantNTP> ntp(new TestableInstantNTP(
-      instant_controller(), instant_url));
-  ntp.reset(new TestableInstantNTP(instant_controller(), instant_url));
-  ntp->set_is_local(false);
-  instant_controller()->set_ntp(ntp.get());
-  instant_controller()->set_javascript_enabled(true);
-  instant_controller()->set_extended_enabled(true);
-  instant_controller()->set_instant_url(instant_url);
-  ntp->set_instant_url("http://local_instant_url");
-  ntp->set_supports_instant(true);
-  instant_controller()->set_in_startup(false);
-  EXPECT_FALSE(instant_controller()->ShouldSwitchToLocalNTP());
-}
-
-TEST_F(InstantControllerTest, SwitchesToLocalNTPIfJSDisabled) {
-  std::string instant_url("http://instant_url");
-  scoped_ptr<TestableInstantNTP> ntp(new TestableInstantNTP(
-      instant_controller(), instant_url));
-  ntp.reset(new TestableInstantNTP(instant_controller(), instant_url));
-  ntp->set_is_local(false);
-  instant_controller()->set_ntp(ntp.get());
-  instant_controller()->set_javascript_enabled(false);
-  instant_controller()->set_extended_enabled(true);
-  instant_controller()->set_instant_url(instant_url);
-  ntp->set_instant_url("http://local_instant_url");
-  ntp->set_supports_instant(true);
-  instant_controller()->set_in_startup(false);
-  EXPECT_TRUE(instant_controller()->ShouldSwitchToLocalNTP());
-}
-
-TEST_F(InstantControllerTest, SwitchesToLocalNTPIfNoNTPReady) {
-  EXPECT_TRUE(instant_controller()->ShouldSwitchToLocalNTP());
-}
-
-TEST_F(InstantControllerTest, IsJavascriptEnabled) {
-  instant_controller()->set_override_javascript_enabled(false);
-  EXPECT_TRUE(instant_controller()->IsJavascriptEnabled());
-}
-
-TEST_F(InstantControllerTest, IsJavascriptEnabledChecksContentSettings) {
-  instant_controller()->set_override_javascript_enabled(false);
-  instant_controller()->profile()->GetHostContentSettingsMap()
-      ->SetDefaultContentSetting(CONTENT_SETTINGS_TYPE_JAVASCRIPT,
-                                 CONTENT_SETTING_DEFAULT);
-  EXPECT_TRUE(instant_controller()->IsJavascriptEnabled());
-  instant_controller()->profile()->GetHostContentSettingsMap()
-      ->SetDefaultContentSetting(CONTENT_SETTINGS_TYPE_JAVASCRIPT,
-                                 CONTENT_SETTING_ALLOW);
-  EXPECT_TRUE(instant_controller()->IsJavascriptEnabled());
-  instant_controller()->profile()->GetHostContentSettingsMap()
-      ->SetDefaultContentSetting(CONTENT_SETTINGS_TYPE_JAVASCRIPT,
-                                 CONTENT_SETTING_BLOCK);
-  EXPECT_FALSE(instant_controller()->IsJavascriptEnabled());
-}
-
-TEST_F(InstantControllerTest, IsJavascriptEnabledChecksPrefs) {
-  instant_controller()->set_override_javascript_enabled(false);
-  instant_controller()->profile()->GetPrefs()->SetBoolean(
-      prefs::kWebKitJavascriptEnabled, true);
-  EXPECT_TRUE(instant_controller()->IsJavascriptEnabled());
-  instant_controller()->profile()->GetPrefs()->SetBoolean(
-      prefs::kWebKitJavascriptEnabled, false);
-  EXPECT_FALSE(instant_controller()->IsJavascriptEnabled());
-}
diff --git a/chrome/browser/ui/search/instant_extended_interactive_uitest.cc b/chrome/browser/ui/search/instant_extended_interactive_uitest.cc
index f9f51f4..7d2f2c8 100644
--- a/chrome/browser/ui/search/instant_extended_interactive_uitest.cc
+++ b/chrome/browser/ui/search/instant_extended_interactive_uitest.cc
@@ -45,6 +45,7 @@
 #include "chrome/browser/ui/browser_tabstrip.h"
 #include "chrome/browser/ui/omnibox/omnibox_view.h"
 #include "chrome/browser/ui/search/instant_ntp.h"
+#include "chrome/browser/ui/search/instant_ntp_prerenderer.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"
@@ -350,26 +351,33 @@
   ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
   FocusOmniboxAndWaitForInstantNTPSupport();
 
+  InstantService* instant_service =
+      InstantServiceFactory::GetForProfile(browser()->profile());
+  ASSERT_NE(static_cast<InstantService*>(NULL), instant_service);
+
   // 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());
+  // InstantNTPPrerenderer has already registered itself. So the
+  // InstantNTPPrerenderer needs to register itself as NetworkChangeObserver
+  // again.
+  net::NetworkChangeNotifier::AddNetworkChangeObserver(
+      instant_service->ntp_prerenderer());
 
   // 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());
-  EXPECT_TRUE(instant()->ntp()->IsLocal());
+  ASSERT_NE(static_cast<InstantNTP*>(NULL),
+            instant_service->ntp_prerenderer()->ntp());
+  EXPECT_TRUE(instant_service->ntp_prerenderer()->ntp()->IsLocal());
 
   // Change the connect state, and wait for the notifications to be run, and NTP
   // support to be determined.
   SetConnectionType(net::NetworkChangeNotifier::CONNECTION_ETHERNET);
   FocusOmniboxAndWaitForInstantNTPSupport();
 
-  // Verify the network state is fine, and instant controller doesn't want to
-  // switch to local NTP anymore.
+  // Verify the network state is fine, and InstantNTPPrerenderer doesn't want
+  // to switch to local NTP anymore.
   EXPECT_FALSE(net::NetworkChangeNotifier::IsOffline());
-  EXPECT_FALSE(instant()->ShouldSwitchToLocalNTP());
+  EXPECT_FALSE(instant_service->ntp_prerenderer()->ShouldSwitchToLocalNTP());
 
   // Open new tab.
   ui_test_utils::NavigateToURLWithDisposition(
@@ -382,17 +390,19 @@
 
   // 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());
+  EXPECT_NE(instant_service->ntp_prerenderer()->GetLocalInstantURL(),
+            active_tab->GetURL().spec());
+  ASSERT_NE(static_cast<InstantNTP*>(NULL),
+            instant_service->ntp_prerenderer()->ntp());
+  EXPECT_FALSE(instant_service->ntp_prerenderer()->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.
+  // Verify the network state is fine, and InstantNTPPrerenderer doesn't want
+  // to switch to local NTP anymore.
   EXPECT_TRUE(net::NetworkChangeNotifier::IsOffline());
-  EXPECT_TRUE(instant()->ShouldSwitchToLocalNTP());
+  EXPECT_TRUE(instant_service->ntp_prerenderer()->ShouldSwitchToLocalNTP());
 
   // Open new tab. Preloaded NTP contents should have been used.
   ui_test_utils::NavigateToURLWithDisposition(
@@ -404,9 +414,11 @@
 
   // 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());
+  EXPECT_EQ(instant_service->ntp_prerenderer()->GetLocalInstantURL(),
+            active_tab->GetURL().spec());
+  ASSERT_NE(static_cast<InstantNTP*>(NULL),
+            instant_service->ntp_prerenderer()->ntp());
+  EXPECT_TRUE(instant_service->ntp_prerenderer()->ntp()->IsLocal());
 }
 
 #if defined(HTML_INSTANT_EXTENDED_POPUP)
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 6035c1b..af3206f 100644
--- a/chrome/browser/ui/search/instant_extended_manual_interactive_uitest.cc
+++ b/chrome/browser/ui/search/instant_extended_manual_interactive_uitest.cc
@@ -4,6 +4,8 @@
 
 #include "base/strings/string_util.h"
 #include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/search/instant_service.h"
+#include "chrome/browser/search/instant_service_factory.h"
 #include "chrome/browser/search/search.h"
 #include "chrome/browser/task_manager/task_manager.h"
 #include "chrome/browser/task_manager/task_manager_browsertest_util.h"
@@ -11,7 +13,7 @@
 #include "chrome/browser/ui/browser_commands.h"
 #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_ntp_prerenderer.h"
 #include "chrome/browser/ui/search/instant_test_utils.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/common/omnibox_focus_state.h"
@@ -93,9 +95,12 @@
 
 IN_PROC_BROWSER_TEST_F(InstantExtendedManualTest, MANUAL_ShowsGoogleNTP) {
   set_browser(browser());
-  instant()->ReloadStaleNTP();
-  FocusOmniboxAndWaitForInstantNTPSupport();
+  InstantService* instant_service =
+      InstantServiceFactory::GetForProfile(browser()->profile());
+  ASSERT_NE(static_cast<InstantService*>(NULL), instant_service);
+  instant_service->ntp_prerenderer()->ReloadStaleNTP();
 
+  FocusOmniboxAndWaitForInstantNTPSupport();
   content::WindowedNotificationObserver observer(
       content::NOTIFICATION_NAV_ENTRY_COMMITTED,
       content::NotificationService::AllSources());
@@ -112,9 +117,12 @@
 
 IN_PROC_BROWSER_TEST_F(InstantExtendedManualTest, MANUAL_SearchesFromFakebox) {
   set_browser(browser());
-  instant()->ReloadStaleNTP();
-  FocusOmniboxAndWaitForInstantNTPSupport();
+  InstantService* instant_service =
+      InstantServiceFactory::GetForProfile(browser()->profile());
+  ASSERT_NE(static_cast<InstantService*>(NULL), instant_service);
+  instant_service->ntp_prerenderer()->ReloadStaleNTP();
 
+  FocusOmniboxAndWaitForInstantNTPSupport();
   // Open a new tab page.
   content::WindowedNotificationObserver observer(
       content::NOTIFICATION_NAV_ENTRY_COMMITTED,
diff --git a/chrome/browser/ui/search/instant_loader.cc b/chrome/browser/ui/search/instant_loader.cc
index c50b7fb..d6d467d 100644
--- a/chrome/browser/ui/search/instant_loader.cc
+++ b/chrome/browser/ui/search/instant_loader.cc
@@ -7,7 +7,6 @@
 #include "chrome/browser/content_settings/tab_specific_content_settings.h"
 #include "chrome/browser/extensions/api/web_navigation/web_navigation_api.h"
 #include "chrome/browser/favicon/favicon_tab_helper.h"
-#include "chrome/browser/history/history_tab_helper.h"
 #include "chrome/browser/safe_browsing/safe_browsing_tab_observer.h"
 #include "chrome/browser/search/search.h"
 #include "chrome/browser/tab_contents/tab_util.h"
@@ -42,7 +41,6 @@
 
 void InstantLoader::Init(const GURL& instant_url,
                          Profile* profile,
-                         const content::WebContents* active_tab,
                          const base::Closure& on_stale_callback) {
   content::WebContents::CreateParams create_params(profile);
   create_params.site_instance = content::SiteInstance::CreateForURL(
@@ -104,9 +102,7 @@
   CoreTabHelper::CreateForWebContents(contents());
   CoreTabHelper::FromWebContents(contents())->set_delegate(this);
 
-  // Tab helpers used when committing an overlay.
   SearchTabHelper::CreateForWebContents(contents());
-  HistoryTabHelper::CreateForWebContents(contents());
 
   // Observers.
   extensions::WebNavigationTabObserver::CreateForWebContents(contents());
@@ -127,11 +123,6 @@
                  content::Source<content::NavigationController>(
                      &contents_->GetController()));
 #endif
-
-  // When the WebContents finishes loading it should be checked to ensure that
-  // it is in the instant process.
-  registrar_.Add(this, content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
-                 content::Source<content::WebContents>(contents_.get()));
 }
 
 scoped_ptr<content::WebContents> InstantLoader::ReleaseContents() {
@@ -155,23 +146,12 @@
                     content::Source<content::NavigationController>(
                         &contents_->GetController()));
 #endif
-  registrar_.Remove(this, content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
-                    content::Source<content::WebContents>(contents_.get()));
-
   return contents_.Pass();
 }
 
 void InstantLoader::Observe(int type,
                             const content::NotificationSource& source,
                             const content::NotificationDetails& details) {
-  if (type == content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME) {
-    const content::WebContents* web_contents =
-        content::Source<content::WebContents>(source).ptr();
-    DCHECK_EQ(contents_.get(), web_contents);
-    delegate_->LoadCompletedMainFrame();
-    return;
-  }
-
 #if defined(OS_MACOSX)
   if (type == content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED) {
     if (content::RenderWidgetHostView* rwhv =
@@ -202,14 +182,6 @@
   return false;
 }
 
-void InstantLoader::LostCapture() {
-  delegate_->OnMouseUp();
-}
-
-void InstantLoader::WebContentsFocused(content::WebContents* /* contents */) {
-  delegate_->OnFocus();
-}
-
 void InstantLoader::CanDownload(content::RenderViewHost* /* render_view_host */,
                                 int /* request_id */,
                                 const std::string& /* request_method */,
@@ -218,29 +190,6 @@
   callback.Run(false);
 }
 
-void InstantLoader::HandleMouseDown() {
-  delegate_->OnMouseDown();
-}
-
-void InstantLoader::HandleMouseUp() {
-  delegate_->OnMouseUp();
-}
-
-void InstantLoader::HandlePointerActivate() {
-  delegate_->OnMouseDown();
-}
-
-void InstantLoader::HandleGestureEnd() {
-  delegate_->OnMouseUp();
-}
-
-void InstantLoader::DragEnded() {
-  // If the user drags, we won't get a mouse up (at least on Linux). Commit
-  // the Instant result when the drag ends, so that during the drag the page
-  // won't move around.
-  delegate_->OnMouseUp();
-}
-
 bool InstantLoader::OnGoToEntryOffset(int /* offset */) {
   return false;
 }
diff --git a/chrome/browser/ui/search/instant_loader.h b/chrome/browser/ui/search/instant_loader.h
index e0ec012..36aef11 100644
--- a/chrome/browser/ui/search/instant_loader.h
+++ b/chrome/browser/ui/search/instant_loader.h
@@ -24,8 +24,7 @@
 }
 
 // InstantLoader is used to create and maintain a WebContents where we can
-// preload a page into. It is used by InstantOverlay and InstantNTP to
-// preload an Instant page.
+// preload a page into. It is used by InstantNTP to preload an Instant page.
 class InstantLoader : public content::NotificationObserver,
                       public content::WebContentsDelegate,
                       public CoreTabHelperDelegate {
@@ -37,15 +36,6 @@
     // Called after someone has swapped in a different WebContents for ours.
     virtual void OnSwappedContents() = 0;
 
-    // Called when the underlying contents receive focus.
-    virtual void OnFocus() = 0;
-
-    // Called when the mouse pointer is down.
-    virtual void OnMouseDown() = 0;
-
-    // Called when the mouse pointer is released (or a drag event ends).
-    virtual void OnMouseUp() = 0;
-
     // Called to open a URL using the underlying contents (see
     // WebContentsDelegate::OpenURLFromTab). The Delegate should return the
     // WebContents the URL is opened in, or NULL if the URL wasn't opened
@@ -54,9 +44,6 @@
         content::WebContents* source,
         const content::OpenURLParams& params) = 0;
 
-    // Called when a main frame load is complete.
-    virtual void LoadCompletedMainFrame() = 0;
-
    protected:
     ~Delegate();
   };
@@ -66,12 +53,10 @@
 
   // Creates a new WebContents in the context of |profile| that will be used to
   // load |instant_url|. The page is not actually loaded until Load() is
-  // called. Uses |active_contents|, if non-NULL, to initialize the size of the
-  // new contents. |on_stale_callback| will be called after kStalePageTimeoutMS
+  // called. |on_stale_callback| will be called after kStalePageTimeoutMS
   // has elapsed after Load() being called.
   void Init(const GURL& instant_url,
             Profile* profile,
-            const content::WebContents* active_contents,
             const base::Closure& on_stale_callback);
 
   // Loads |instant_url_| in |contents_|.
@@ -101,17 +86,10 @@
   // Overridden from content::WebContentsDelegate:
   virtual bool ShouldSuppressDialogs() OVERRIDE;
   virtual bool ShouldFocusPageAfterCrash() OVERRIDE;
-  virtual void LostCapture() OVERRIDE;
-  virtual void WebContentsFocused(content::WebContents* contents) OVERRIDE;
   virtual void CanDownload(content::RenderViewHost* render_view_host,
                            int request_id,
                            const std::string& request_method,
                            const base::Callback<void(bool)>& callback) OVERRIDE;
-  virtual void HandleMouseDown() OVERRIDE;
-  virtual void HandleMouseUp() OVERRIDE;
-  virtual void HandlePointerActivate() OVERRIDE;
-  virtual void HandleGestureEnd() OVERRIDE;
-  virtual void DragEnded() OVERRIDE;
   virtual bool OnGoToEntryOffset(int offset) OVERRIDE;
   virtual content::WebContents* OpenURLFromTab(
       content::WebContents* source,
diff --git a/chrome/browser/ui/search/instant_ntp.cc b/chrome/browser/ui/search/instant_ntp.cc
index 0ccc9b0..08274f6 100644
--- a/chrome/browser/ui/search/instant_ntp.cc
+++ b/chrome/browser/ui/search/instant_ntp.cc
@@ -5,27 +5,31 @@
 #include "chrome/browser/ui/search/instant_ntp.h"
 
 #include "base/metrics/histogram.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/search/instant_ntp_prerenderer.h"
 #include "chrome/browser/ui/search/search_tab_helper.h"
 #include "chrome/browser/ui/webui/ntp/ntp_user_data_logger.h"
 #include "content/public/browser/web_contents.h"
 #include "url/gurl.h"
 
-InstantNTP::InstantNTP(InstantPage::Delegate* delegate,
+InstantNTP::InstantNTP(InstantNTPPrerenderer* ntp_prerenderer,
                        const std::string& instant_url,
-                       bool is_incognito)
-    : InstantPage(delegate, instant_url, is_incognito),
-      loader_(this) {
-  DCHECK(delegate);
+                       Profile* profile)
+    : InstantPage(ntp_prerenderer, instant_url, profile,
+                  profile->IsOffTheRecord()),
+      loader_(this),
+      ntp_prerenderer_(ntp_prerenderer) {
 }
 
 InstantNTP::~InstantNTP() {
+  if (contents())
+    ReleaseContents().reset();
 }
 
-void InstantNTP::InitContents(Profile* profile,
-                              const content::WebContents* active_tab,
-                              const base::Closure& on_stale_callback) {
+void InstantNTP::InitContents(const base::Closure& on_stale_callback) {
+  DCHECK(!contents());
   GURL instantNTP_url(instant_url());
-  loader_.Init(instantNTP_url, profile, active_tab, on_stale_callback);
+  loader_.Init(instantNTP_url, profile(), on_stale_callback);
   SetContents(loader_.contents());
   content::WebContents* content = contents();
   SearchTabHelper::FromWebContents(content)->InitForPreloadedNTP();
@@ -42,34 +46,20 @@
 }
 
 void InstantNTP::RenderViewCreated(content::RenderViewHost* render_view_host) {
-  delegate()->InstantPageRenderViewCreated(contents());
+  InitializeFonts();
+  InitializePromos();
 }
 
 void InstantNTP::RenderProcessGone(base::TerminationStatus /* status */) {
-  delegate()->InstantPageRenderProcessGone(contents());
+  ntp_prerenderer_->RenderProcessGone();
 }
 
 void InstantNTP::OnSwappedContents() {
   SetContents(loader_.contents());
 }
 
-void InstantNTP::OnFocus() {
-  NOTREACHED();
-}
-
-void InstantNTP::OnMouseDown() {
-  NOTREACHED();
-}
-
-void InstantNTP::OnMouseUp() {
-  NOTREACHED();
-}
-
 content::WebContents* InstantNTP::OpenURLFromTab(
     content::WebContents* source,
     const content::OpenURLParams& params) {
   return NULL;
 }
-
-void InstantNTP::LoadCompletedMainFrame() {
-}
diff --git a/chrome/browser/ui/search/instant_ntp.h b/chrome/browser/ui/search/instant_ntp.h
index 152451a..0505f25 100644
--- a/chrome/browser/ui/search/instant_ntp.h
+++ b/chrome/browser/ui/search/instant_ntp.h
@@ -9,15 +9,18 @@
 
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
+#include "base/gtest_prod_util.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 InstantNTPPrerenderer;
 class Profile;
 
 namespace content {
 class RenderViewHost;
+class WebContents;
 }
 
 // InstantNTP is used to preload an Instant page that will be swapped in when a
@@ -26,40 +29,38 @@
 class InstantNTP : public InstantPage,
                    public InstantLoader::Delegate {
  public:
-  InstantNTP(InstantPage::Delegate* delegate, const std::string& instant_url,
-             bool is_incognito);
+  InstantNTP(InstantNTPPrerenderer* delegate,
+             const std::string& instant_url,
+             Profile* profile);
   virtual ~InstantNTP();
 
-  // Creates a new WebContents and loads |instant_url_| into it. Uses
-  // |active_tab|, if non-NULL, to initialize the size of the WebContents.
+  // Creates a new WebContents and loads |instant_url_| into it.
   // |on_stale_callback| will be called when |loader_| determines the page to
   // be stale.
-  void InitContents(Profile* profile,
-                    const content::WebContents* active_tab,
-                    const base::Closure& on_stale_callback);
+  void InitContents(const base::Closure& on_stale_callback);
 
   // Releases the WebContents for the Instant page.  This should be called when
   // the page is about to be committed.
   scoped_ptr<content::WebContents> ReleaseContents();
 
  private:
+  FRIEND_TEST_ALL_PREFIXES(InstantExtendedNetworkTest,
+                           NTPReactsToNetworkChanges);
+
   // Overridden from content::WebContentsObserver:
   virtual void RenderViewCreated(
       content::RenderViewHost* render_view_host) OVERRIDE;
   virtual void RenderProcessGone(
       base::TerminationStatus status) OVERRIDE;
 
-  // Overriden from InstantLoader::Delegate:
+  // Overridden 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;
 
   InstantLoader loader_;
+  InstantNTPPrerenderer* const ntp_prerenderer_;
 
   DISALLOW_COPY_AND_ASSIGN(InstantNTP);
 };
diff --git a/chrome/browser/ui/search/instant_ntp_prerenderer.cc b/chrome/browser/ui/search/instant_ntp_prerenderer.cc
new file mode 100644
index 0000000..7a4c131
--- /dev/null
+++ b/chrome/browser/ui/search/instant_ntp_prerenderer.cc
@@ -0,0 +1,284 @@
+// Copyright 2013 The Chromium Authors. 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_ntp_prerenderer.h"
+
+#include "base/basictypes.h"
+#include "base/bind.h"
+#include "base/message_loop/message_loop.h"
+#include "base/prefs/pref_service.h"
+#include "build/build_config.h"
+#include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/content_settings/content_settings_provider.h"
+#include "chrome/browser/content_settings/host_content_settings_map.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"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_finder.h"
+#include "chrome/browser/ui/host_desktop.h"
+#include "chrome/browser/ui/search/instant_ntp.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/common/content_settings.h"
+#include "chrome/common/pref_names.h"
+#include "content/public/browser/notification_service.h"
+#include "net/base/network_change_notifier.h"
+
+namespace {
+
+void DeleteNTPSoon(scoped_ptr<InstantNTP> ntp) {
+  if (!ntp)
+    return;
+
+  if (ntp->contents()) {
+    base::MessageLoop::current()->DeleteSoon(
+        FROM_HERE, ntp->ReleaseContents().release());
+  }
+  base::MessageLoop::current()->DeleteSoon(FROM_HERE, ntp.release());
+}
+
+}  // namespace
+
+
+InstantNTPPrerenderer::InstantNTPPrerenderer(Profile* profile,
+                                             PrefService* prefs)
+    : profile_(profile),
+      extended_enabled_(chrome::IsInstantExtendedAPIEnabled()) {
+  DCHECK(profile);
+
+  // In unit tests, prefs may be NULL.
+  if (prefs) {
+    profile_pref_registrar_.Init(prefs);
+    profile_pref_registrar_.Add(
+        prefs::kSearchSuggestEnabled,
+        base::Bind(&InstantNTPPrerenderer::ReloadStaleNTP,
+                   base::Unretained(this)));
+    profile_pref_registrar_.Add(
+        prefs::kDefaultSearchProviderID,
+        base::Bind(&InstantNTPPrerenderer::OnDefaultSearchProviderChanged,
+                   base::Unretained(this)));
+  }
+  net::NetworkChangeNotifier::AddNetworkChangeObserver(this);
+}
+
+InstantNTPPrerenderer::~InstantNTPPrerenderer() {
+  net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
+}
+
+void InstantNTPPrerenderer::PreloadInstantNTP() {
+  DCHECK(!ntp());
+  ReloadStaleNTP();
+}
+
+scoped_ptr<content::WebContents> InstantNTPPrerenderer::ReleaseNTPContents() {
+  if (!extended_enabled() || !profile_ || profile_->IsOffTheRecord() ||
+      !chrome::ShouldShowInstantNTP())
+    return scoped_ptr<content::WebContents>();
+
+  if (ShouldSwitchToLocalNTP())
+    ResetNTP(GetLocalInstantURL());
+
+  scoped_ptr<content::WebContents> ntp_contents = ntp_->ReleaseContents();
+
+  // Preload a new InstantNTP.
+  ResetNTP(GetInstantURL());
+  return ntp_contents.Pass();
+}
+
+content::WebContents* InstantNTPPrerenderer::GetNTPContents() const {
+  return ntp() ? ntp()->contents() : NULL;
+}
+
+void InstantNTPPrerenderer::DeleteNTPContents() {
+  if (ntp_)
+    ntp_.reset();
+}
+
+void InstantNTPPrerenderer::RenderProcessGone() {
+  DeleteNTPSoon(ntp_.Pass());
+}
+
+std::string InstantNTPPrerenderer::GetLocalInstantURL() const {
+  return chrome::GetLocalInstantURL(profile_).spec();
+}
+
+std::string InstantNTPPrerenderer::GetInstantURL() const {
+  if (net::NetworkChangeNotifier::IsOffline())
+    return GetLocalInstantURL();
+
+  // TODO(kmadhusu): Remove start margin param from chrome::GetInstantURL().
+  const GURL instant_url = chrome::GetInstantURL(profile_,
+                                                 chrome::kDisableStartMargin);
+  if (!instant_url.is_valid())
+    return GetLocalInstantURL();
+
+  return instant_url.spec();
+}
+
+bool InstantNTPPrerenderer::IsJavascriptEnabled() const {
+  GURL instant_url(GetInstantURL());
+  GURL origin(instant_url.GetOrigin());
+  ContentSetting js_setting = profile_->GetHostContentSettingsMap()->
+      GetContentSetting(origin, origin, CONTENT_SETTINGS_TYPE_JAVASCRIPT,
+                        NO_RESOURCE_IDENTIFIER);
+  // Javascript can be disabled either in content settings or via a WebKit
+  // preference, so check both. Disabling it through the Settings page affects
+  // content settings. I'm not sure how to disable the WebKit preference, but
+  // it's theoretically possible some users have it off.
+  bool js_content_enabled =
+      js_setting == CONTENT_SETTING_DEFAULT ||
+      js_setting == CONTENT_SETTING_ALLOW;
+  bool js_webkit_enabled = profile_->GetPrefs()->GetBoolean(
+      prefs::kWebKitJavascriptEnabled);
+  return js_content_enabled && js_webkit_enabled;
+}
+
+bool InstantNTPPrerenderer::InStartup() const {
+#if !defined(OS_ANDROID)
+  // TODO(kmadhusu): This is not completely reliable. Find a better way to
+  // detect startup time.
+  Browser* browser = chrome::FindBrowserWithProfile(profile_,
+                                                    chrome::GetActiveDesktop());
+  return !browser || !browser->tab_strip_model()->GetActiveWebContents();
+#endif
+  return false;
+}
+
+InstantNTP* InstantNTPPrerenderer::ntp() const {
+  return ntp_.get();
+}
+
+bool InstantNTPPrerenderer::extended_enabled() const {
+  return extended_enabled_;
+}
+
+void InstantNTPPrerenderer::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());
+}
+
+void InstantNTPPrerenderer::InstantSupportDetermined(
+    const content::WebContents* contents,
+    bool supports_instant) {
+  DCHECK(ntp() && ntp()->contents() == contents);
+
+  if (!supports_instant) {
+    bool is_local = ntp()->IsLocal();
+    DeleteNTPSoon(ntp_.Pass());
+    if (!is_local)
+      ResetNTP(GetLocalInstantURL());
+  }
+
+  content::NotificationService::current()->Notify(
+      chrome::NOTIFICATION_INSTANT_NTP_SUPPORT_DETERMINED,
+      content::Source<InstantNTPPrerenderer>(this),
+      content::NotificationService::NoDetails());
+}
+
+void InstantNTPPrerenderer::InstantPageAboutToNavigateMainFrame(
+    const content::WebContents* contents,
+    const GURL& url) {
+  NOTREACHED();
+}
+
+void InstantNTPPrerenderer::FocusOmnibox(const content::WebContents* contents,
+                                         OmniboxFocusState state) {
+  NOTREACHED();
+}
+
+void InstantNTPPrerenderer::NavigateToURL(const content::WebContents* contents,
+                                          const GURL& url,
+                                          content::PageTransition transition,
+                                          WindowOpenDisposition disposition,
+                                          bool is_search_type) {
+  NOTREACHED();
+}
+
+void InstantNTPPrerenderer::DeleteMostVisitedItem(const GURL& url) {
+  NOTREACHED();
+}
+
+void InstantNTPPrerenderer::UndoMostVisitedDeletion(const GURL& url) {
+  NOTREACHED();
+}
+
+void InstantNTPPrerenderer::UndoAllMostVisitedDeletions() {
+  NOTREACHED();
+}
+
+void InstantNTPPrerenderer::InstantPageLoadFailed(
+    content::WebContents* contents) {
+  DCHECK(ntp() && ntp()->contents() == contents);
+
+  bool is_local = ntp()->IsLocal();
+  DeleteNTPSoon(ntp_.Pass());
+  if (!is_local)
+    ResetNTP(GetLocalInstantURL());
+}
+
+void InstantNTPPrerenderer::OnDefaultSearchProviderChanged(
+    const std::string& pref_name) {
+  DCHECK_EQ(pref_name, std::string(prefs::kDefaultSearchProviderID));
+  if (!extended_enabled() || !ntp())
+    return;
+
+  ResetNTP(GetInstantURL());
+}
+
+void InstantNTPPrerenderer::ResetNTP(const std::string& instant_url) {
+  // 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, profile_));
+  ntp_->InitContents(base::Bind(&InstantNTPPrerenderer::ReloadStaleNTP,
+                                base::Unretained(this)));
+}
+
+void InstantNTPPrerenderer::ReloadStaleNTP() {
+  if (!extended_enabled())
+    return;
+
+  ResetNTP(GetInstantURL());
+}
+
+bool InstantNTPPrerenderer::PageIsCurrent() const {
+  const std::string& instant_url = GetInstantURL();
+  if (instant_url.empty() ||
+      !chrome::MatchesOriginAndPath(GURL(ntp()->instant_url()),
+                                    GURL(instant_url)))
+    return false;
+
+  return ntp()->supports_instant();
+}
+
+bool InstantNTPPrerenderer::ShouldSwitchToLocalNTP() const {
+  if (!ntp())
+    return true;
+
+  // Assume users with Javascript disabled do not want the online experience.
+  if (!IsJavascriptEnabled())
+    return true;
+
+  // Already a local page. Not calling IsLocal() because we want to distinguish
+  // between the Google-specific and generic local NTP.
+  if (extended_enabled() && ntp()->instant_url() == GetLocalInstantURL())
+    return false;
+
+  if (PageIsCurrent())
+    return false;
+
+  // The preloaded NTP does not support instant yet. If we're not in startup,
+  // always fall back to the local NTP. If we are in startup, use the local NTP
+  // (unless the finch flag to use the remote NTP is set).
+  return !(InStartup() && chrome::ShouldPreferRemoteNTPOnStartup());
+}
diff --git a/chrome/browser/ui/search/instant_ntp_prerenderer.h b/chrome/browser/ui/search/instant_ntp_prerenderer.h
new file mode 100644
index 0000000..cf0c0d3
--- /dev/null
+++ b/chrome/browser/ui/search/instant_ntp_prerenderer.h
@@ -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.
+
+#ifndef CHROME_BROWSER_UI_SEARCH_INSTANT_NTP_PRERENDERER_H_
+#define CHROME_BROWSER_UI_SEARCH_INSTANT_NTP_PRERENDERER_H_
+
+#include <string>
+
+#include "base/compiler_specific.h"
+#include "base/gtest_prod_util.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/prefs/pref_change_registrar.h"
+#include "chrome/browser/ui/search/instant_page.h"
+#include "content/public/browser/web_contents.h"
+#include "net/base/network_change_notifier.h"
+
+class InstantExtendedTest;
+class InstantNTP;
+class InstantService;
+class InstantTestBase;
+class Profile;
+
+// InstantNTPPrerenderer maintains a prerendered instance of InstantNTP.
+//
+// An InstantNTP instance is a preloaded search page that will be swapped-in the
+// next time when the user navigates to the New Tab Page. It is never shown to
+// the user in an uncommitted state. It is backed by a WebContents and that is
+// owned by InstantNTP.
+//
+// InstantNTPPrerenderer is owned by InstantService.
+class InstantNTPPrerenderer
+    : public InstantPage::Delegate,
+      public net::NetworkChangeNotifier::NetworkChangeObserver {
+ public:
+  InstantNTPPrerenderer(Profile* profile, PrefService* prefs);
+  virtual ~InstantNTPPrerenderer();
+
+  // Preloads |ntp_| with a new InstantNTP.
+  void PreloadInstantNTP();
+
+  // Releases and returns the InstantNTP WebContents. May be NULL. Loads a new
+  // WebContents for the InstantNTP.
+  scoped_ptr<content::WebContents> ReleaseNTPContents() WARN_UNUSED_RESULT;
+
+  // The NTP WebContents. May be NULL. InstantNTPPrerenderer retains ownership.
+  content::WebContents* GetNTPContents() const;
+
+  // Invoked to null out |ntp_|.
+  void DeleteNTPContents();
+
+  // Invoked when the InstantNTP renderer process crashes.
+  void RenderProcessGone();
+
+ protected:
+  // Returns the local Instant URL. (Just a convenience wrapper to get the local
+  // Instant URL from InstantService.)
+  virtual std::string GetLocalInstantURL() const;
+
+  // Returns the correct Instant URL to use from the following possibilities:
+  //     o The default search engine's Instant URL.
+  //     o The local page (see GetLocalInstantURL())
+  // Returns an 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).
+  virtual std::string GetInstantURL() const;
+
+  // Returns true if Javascript is enabled and false otherwise.
+  virtual bool IsJavascriptEnabled() const;
+
+  // Returns true if the browser is in startup.
+  virtual bool InStartup() const;
+
+  // Accessors are made protected for testing purposes.
+  virtual InstantNTP* ntp() const;
+  virtual bool extended_enabled() const;
+
+  Profile* profile() const {
+    return profile_;
+  }
+
+ private:
+  friend class InstantExtendedTest;
+  friend class InstantNTPPrerendererTest;
+  friend class InstantTestBase;
+
+  FRIEND_TEST_ALL_PREFIXES(InstantExtendedNetworkTest,
+                           NTPReactsToNetworkChanges);
+  FRIEND_TEST_ALL_PREFIXES(InstantNTPPrerendererTest,
+                           PrefersRemoteNTPOnStartup);
+  FRIEND_TEST_ALL_PREFIXES(InstantNTPPrerendererTest,
+                           SwitchesToLocalNTPIfNoInstantSupport);
+  FRIEND_TEST_ALL_PREFIXES(InstantNTPPrerendererTest,
+                           SwitchesToLocalNTPIfPathBad);
+  FRIEND_TEST_ALL_PREFIXES(InstantNTPPrerendererTest,
+                           DoesNotSwitchToLocalNTPIfOnCurrentNTP);
+  FRIEND_TEST_ALL_PREFIXES(InstantNTPPrerendererTest,
+                           DoesNotSwitchToLocalNTPIfOnLocalNTP);
+  FRIEND_TEST_ALL_PREFIXES(InstantNTPPrerendererTest,
+                           SwitchesToLocalNTPIfJSDisabled);
+  FRIEND_TEST_ALL_PREFIXES(InstantNTPPrerendererTest,
+                           SwitchesToLocalNTPIfNoNTPReady);
+  FRIEND_TEST_ALL_PREFIXES(InstantNTPPrerendererTest,
+                           IsJavascriptEnabled);
+  FRIEND_TEST_ALL_PREFIXES(InstantNTPPrerendererTest,
+                           IsJavascriptEnabledChecksContentSettings);
+  FRIEND_TEST_ALL_PREFIXES(InstantNTPPrerendererTest,
+                           IsJavascriptEnabledChecksPrefs);
+  FRIEND_TEST_ALL_PREFIXES(InstantExtendedManualTest, MANUAL_ShowsGoogleNTP);
+  FRIEND_TEST_ALL_PREFIXES(InstantExtendedManualTest,
+                           MANUAL_SearchesFromFakebox);
+
+  // Overridden from net::NetworkChangeNotifier::NetworkChangeObserver:
+  // If the network status changes, resets InstantNTP.
+  virtual void OnNetworkChanged(net::NetworkChangeNotifier::ConnectionType type)
+      OVERRIDE;
+
+  // Overridden from InstantPage::Delegate:
+  virtual void InstantSupportDetermined(const content::WebContents* contents,
+                                        bool supports_instant) OVERRIDE;
+  virtual void InstantPageAboutToNavigateMainFrame(
+      const content::WebContents* contents,
+      const GURL& url) OVERRIDE;
+  virtual void FocusOmnibox(const content::WebContents* contents,
+                            OmniboxFocusState state) OVERRIDE;
+  virtual void NavigateToURL(const content::WebContents* contents,
+                             const GURL& url,
+                             content::PageTransition transition,
+                             WindowOpenDisposition disposition,
+                             bool is_search_type) OVERRIDE;
+  virtual void DeleteMostVisitedItem(const GURL& url) OVERRIDE;
+  virtual void UndoMostVisitedDeletion(const GURL& url) OVERRIDE;
+  virtual void UndoAllMostVisitedDeletions() OVERRIDE;
+  virtual void InstantPageLoadFailed(content::WebContents* contents) OVERRIDE;
+
+  // Called when the default search provider changes. Resets InstantNTP.
+  void OnDefaultSearchProviderChanged(const std::string& pref_name);
+
+  // Recreates |ntp_| using |instant_url|.
+  void ResetNTP(const std::string& instant_url);
+
+  // Resets |ntp_| with a new InstantNTP. Called when |ntp_| is stale or when a
+  // pref is changed.
+  void ReloadStaleNTP();
+
+  // Returns true if |ntp_| has an up-to-date Instant URL and supports Instant.
+  // Note that local URLs will not pass this check.
+  bool PageIsCurrent() const;
+
+  // Returns true if we should switch to using the local NTP.
+  bool ShouldSwitchToLocalNTP() const;
+
+  Profile* profile_;
+
+  // Whether the extended API is enabled.
+  const bool extended_enabled_;
+
+  // Preloaded InstantNTP.
+  scoped_ptr<InstantNTP> ntp_;
+
+  PrefChangeRegistrar profile_pref_registrar_;
+
+  DISALLOW_COPY_AND_ASSIGN(InstantNTPPrerenderer);
+};
+
+#endif  // CHROME_BROWSER_UI_SEARCH_INSTANT_NTP_PRERENDERER_H_
diff --git a/chrome/browser/ui/search/instant_ntp_prerenderer_unittest.cc b/chrome/browser/ui/search/instant_ntp_prerenderer_unittest.cc
new file mode 100644
index 0000000..374c8fd
--- /dev/null
+++ b/chrome/browser/ui/search/instant_ntp_prerenderer_unittest.cc
@@ -0,0 +1,295 @@
+// Copyright 2013 The Chromium Authors. 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/metrics/histogram.h"
+#include "base/metrics/histogram_samples.h"
+#include "base/metrics/statistics_recorder.h"
+#include "base/prefs/pref_service.h"
+#include "chrome/browser/content_settings/host_content_settings_map.h"
+#include "chrome/browser/search/search.h"
+#include "chrome/browser/ui/search/instant_ntp.h"
+#include "chrome/browser/ui/search/instant_ntp_prerenderer.h"
+#include "chrome/common/content_settings.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/test/base/testing_profile.h"
+#include "content/public/test/test_browser_thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using base::HistogramBase;
+using base::HistogramSamples;
+using base::StatisticsRecorder;
+
+class TestableInstantNTP : public InstantNTP {
+ public:
+  TestableInstantNTP(InstantNTPPrerenderer* ntp_prerenderer,
+                     const std::string& instant_url,
+                     Profile* profile)
+      : InstantNTP(ntp_prerenderer, instant_url, profile) {
+  }
+
+  // Overrides from InstantPage
+  virtual bool supports_instant() const OVERRIDE {
+    return test_supports_instant_;
+  }
+
+  virtual bool IsLocal() const OVERRIDE {
+    return test_is_local_;
+  };
+
+  virtual const std::string& instant_url() const OVERRIDE {
+    return test_instant_url_;
+  }
+
+  void set_instant_url(const std::string& instant_url) {
+    test_instant_url_ = instant_url;
+  }
+
+  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 TestableInstantNTPPrerenderer : public InstantNTPPrerenderer {
+ public:
+  explicit TestableInstantNTPPrerenderer(TestingProfile* profile)
+      : InstantNTPPrerenderer(profile, NULL),
+        test_instant_url_("http://test_url"),
+        test_extended_enabled_(true),
+        override_javascript_enabled_(true),
+        test_javascript_enabled_(true),
+        test_in_startup_(false),
+        test_ntp_(NULL) {}
+
+  // Overrides from InstantNTPPrerenderer
+  virtual std::string GetInstantURL() const OVERRIDE {
+    return test_instant_url_;
+  }
+
+  virtual std::string GetLocalInstantURL() const OVERRIDE {
+    return "http://local_instant_url";
+  }
+
+  virtual bool extended_enabled() const OVERRIDE {
+    return test_extended_enabled_;
+  }
+
+  virtual InstantNTP* ntp() const OVERRIDE {
+    return test_ntp_;
+  }
+
+  virtual bool IsJavascriptEnabled() const OVERRIDE {
+    if (override_javascript_enabled_)
+      return test_javascript_enabled_;
+    else
+      return InstantNTPPrerenderer::IsJavascriptEnabled();
+  }
+
+  virtual bool InStartup() const OVERRIDE {
+    return test_in_startup_;
+  }
+
+  void set_instant_url(const std::string& instant_url) {
+    test_instant_url_ = instant_url;
+  }
+
+  void set_extended_enabled(bool extended_enabled) {
+    test_extended_enabled_ = extended_enabled;
+  }
+
+  void set_ntp(InstantNTP* ntp) {
+    test_ntp_ = ntp;
+  }
+
+  void set_javascript_enabled(bool javascript_enabled) {
+    override_javascript_enabled_ = true;
+    test_javascript_enabled_ = javascript_enabled;
+  }
+
+  void set_override_javascript_enabled(bool override_javascript_enabled) {
+    override_javascript_enabled_ = override_javascript_enabled;
+  }
+
+  void set_in_startup(bool in_startup) {
+    test_in_startup_ = in_startup;
+  }
+
+private:
+  std::string test_instant_url_;
+  bool test_extended_enabled_;
+  bool override_javascript_enabled_;
+  bool test_javascript_enabled_;
+  bool test_in_startup_;
+  InstantNTP* test_ntp_;
+};
+
+class InstantNTPPrerendererTest : public testing::Test {
+ public:
+  InstantNTPPrerendererTest()
+      : ui_thread_(content::BrowserThread::UI),
+        instant_ntp_prerenderer_(new TestableInstantNTPPrerenderer(&profile_)) {
+  }
+
+  virtual void SetUp() OVERRIDE {
+    base::StatisticsRecorder::Initialize();
+  }
+
+  TestableInstantNTPPrerenderer* instant_ntp_prerenderer() {
+    return instant_ntp_prerenderer_.get();
+  }
+
+  Profile* profile() {
+    return instant_ntp_prerenderer()->profile();
+  }
+
+ private:
+  content::TestBrowserThread ui_thread_;
+  scoped_ptr<TestableInstantNTPPrerenderer> instant_ntp_prerenderer_;
+  mutable TestingProfile profile_;
+};
+
+TEST_F(InstantNTPPrerendererTest, PrefersRemoteNTPOnStartup) {
+  std::string instant_url("http://instant_url");
+  scoped_ptr<TestableInstantNTP> ntp(new TestableInstantNTP(
+      instant_ntp_prerenderer(), instant_url, profile()));
+  ntp->set_is_local(false);
+  instant_ntp_prerenderer()->set_ntp(ntp.get());
+  instant_ntp_prerenderer()->set_javascript_enabled(true);
+  instant_ntp_prerenderer()->set_extended_enabled(true);
+  instant_ntp_prerenderer()->set_instant_url(instant_url);
+  ntp->set_instant_url(instant_url);
+  ntp->set_supports_instant(false);
+  instant_ntp_prerenderer()->set_in_startup(true);
+  EXPECT_EQ(!chrome::ShouldPreferRemoteNTPOnStartup(),
+            instant_ntp_prerenderer()->ShouldSwitchToLocalNTP());
+}
+
+TEST_F(InstantNTPPrerendererTest, SwitchesToLocalNTPIfNoInstantSupport) {
+  std::string instant_url("http://instant_url");
+  scoped_ptr<TestableInstantNTP> ntp(new TestableInstantNTP(
+      instant_ntp_prerenderer(), instant_url, profile()));
+  ntp.reset(new TestableInstantNTP(instant_ntp_prerenderer(), instant_url,
+                                   profile()));
+  ntp->set_is_local(false);
+  instant_ntp_prerenderer()->set_ntp(ntp.get());
+  instant_ntp_prerenderer()->set_javascript_enabled(true);
+  instant_ntp_prerenderer()->set_extended_enabled(true);
+  instant_ntp_prerenderer()->set_instant_url(instant_url);
+  ntp->set_instant_url(instant_url);
+  ntp->set_supports_instant(false);
+  instant_ntp_prerenderer()->set_in_startup(false);
+  EXPECT_TRUE(instant_ntp_prerenderer()->ShouldSwitchToLocalNTP());
+}
+
+TEST_F(InstantNTPPrerendererTest, SwitchesToLocalNTPIfPathBad) {
+  std::string instant_url("http://instant_url");
+  scoped_ptr<TestableInstantNTP> ntp(new TestableInstantNTP(
+      instant_ntp_prerenderer(), instant_url, profile()));
+  ntp.reset(new TestableInstantNTP(instant_ntp_prerenderer(), instant_url,
+                                   profile()));
+  ntp->set_is_local(false);
+  instant_ntp_prerenderer()->set_ntp(ntp.get());
+  instant_ntp_prerenderer()->set_javascript_enabled(true);
+  instant_ntp_prerenderer()->set_extended_enabled(true);
+  instant_ntp_prerenderer()->set_instant_url("http://bogus_url");
+  ntp->set_instant_url(instant_url);
+  ntp->set_supports_instant(true);
+  instant_ntp_prerenderer()->set_in_startup(false);
+  EXPECT_TRUE(instant_ntp_prerenderer()->ShouldSwitchToLocalNTP());
+}
+
+TEST_F(InstantNTPPrerendererTest, DoesNotSwitchToLocalNTPIfOnCurrentNTP) {
+  std::string instant_url("http://instant_url");
+  scoped_ptr<TestableInstantNTP> ntp(new TestableInstantNTP(
+      instant_ntp_prerenderer(), instant_url, profile()));
+  ntp.reset(new TestableInstantNTP(instant_ntp_prerenderer(), instant_url,
+                                   profile()));
+  ntp->set_is_local(false);
+  instant_ntp_prerenderer()->set_ntp(ntp.get());
+  instant_ntp_prerenderer()->set_javascript_enabled(true);
+  instant_ntp_prerenderer()->set_extended_enabled(true);
+  instant_ntp_prerenderer()->set_instant_url(instant_url);
+  ntp->set_instant_url(instant_url);
+  ntp->set_supports_instant(true);
+  instant_ntp_prerenderer()->set_in_startup(false);
+  EXPECT_FALSE(instant_ntp_prerenderer()->ShouldSwitchToLocalNTP());
+}
+
+TEST_F(InstantNTPPrerendererTest, DoesNotSwitchToLocalNTPIfOnLocalNTP) {
+  std::string instant_url("http://instant_url");
+  scoped_ptr<TestableInstantNTP> ntp(new TestableInstantNTP(
+      instant_ntp_prerenderer(), instant_url, profile()));
+  ntp.reset(new TestableInstantNTP(instant_ntp_prerenderer(), instant_url,
+                                   profile()));
+  ntp->set_is_local(false);
+  instant_ntp_prerenderer()->set_ntp(ntp.get());
+  instant_ntp_prerenderer()->set_javascript_enabled(true);
+  instant_ntp_prerenderer()->set_extended_enabled(true);
+  instant_ntp_prerenderer()->set_instant_url(instant_url);
+  ntp->set_instant_url("http://local_instant_url");
+  ntp->set_supports_instant(true);
+  instant_ntp_prerenderer()->set_in_startup(false);
+  EXPECT_FALSE(instant_ntp_prerenderer()->ShouldSwitchToLocalNTP());
+}
+
+TEST_F(InstantNTPPrerendererTest, SwitchesToLocalNTPIfJSDisabled) {
+  std::string instant_url("http://instant_url");
+  scoped_ptr<TestableInstantNTP> ntp(new TestableInstantNTP(
+      instant_ntp_prerenderer(), instant_url, profile()));
+  ntp.reset(new TestableInstantNTP(instant_ntp_prerenderer(), instant_url,
+                                   profile()));
+  ntp->set_is_local(false);
+  instant_ntp_prerenderer()->set_ntp(ntp.get());
+  instant_ntp_prerenderer()->set_javascript_enabled(false);
+  instant_ntp_prerenderer()->set_extended_enabled(true);
+  instant_ntp_prerenderer()->set_instant_url(instant_url);
+  ntp->set_instant_url("http://local_instant_url");
+  ntp->set_supports_instant(true);
+  instant_ntp_prerenderer()->set_in_startup(false);
+  EXPECT_TRUE(instant_ntp_prerenderer()->ShouldSwitchToLocalNTP());
+}
+
+TEST_F(InstantNTPPrerendererTest, SwitchesToLocalNTPIfNoNTPReady) {
+  EXPECT_TRUE(instant_ntp_prerenderer()->ShouldSwitchToLocalNTP());
+}
+
+TEST_F(InstantNTPPrerendererTest, IsJavascriptEnabled) {
+  instant_ntp_prerenderer()->set_override_javascript_enabled(false);
+  EXPECT_TRUE(instant_ntp_prerenderer()->IsJavascriptEnabled());
+}
+
+TEST_F(InstantNTPPrerendererTest, IsJavascriptEnabledChecksContentSettings) {
+  instant_ntp_prerenderer()->set_override_javascript_enabled(false);
+  instant_ntp_prerenderer()->profile()->GetHostContentSettingsMap()
+      ->SetDefaultContentSetting(CONTENT_SETTINGS_TYPE_JAVASCRIPT,
+                                 CONTENT_SETTING_DEFAULT);
+  EXPECT_TRUE(instant_ntp_prerenderer()->IsJavascriptEnabled());
+  instant_ntp_prerenderer()->profile()->GetHostContentSettingsMap()
+      ->SetDefaultContentSetting(CONTENT_SETTINGS_TYPE_JAVASCRIPT,
+                                 CONTENT_SETTING_ALLOW);
+  EXPECT_TRUE(instant_ntp_prerenderer()->IsJavascriptEnabled());
+  instant_ntp_prerenderer()->profile()->GetHostContentSettingsMap()
+      ->SetDefaultContentSetting(CONTENT_SETTINGS_TYPE_JAVASCRIPT,
+                                 CONTENT_SETTING_BLOCK);
+  EXPECT_FALSE(instant_ntp_prerenderer()->IsJavascriptEnabled());
+}
+
+TEST_F(InstantNTPPrerendererTest, IsJavascriptEnabledChecksPrefs) {
+  instant_ntp_prerenderer()->set_override_javascript_enabled(false);
+  instant_ntp_prerenderer()->profile()->GetPrefs()->SetBoolean(
+      prefs::kWebKitJavascriptEnabled, true);
+  EXPECT_TRUE(instant_ntp_prerenderer()->IsJavascriptEnabled());
+  instant_ntp_prerenderer()->profile()->GetPrefs()->SetBoolean(
+      prefs::kWebKitJavascriptEnabled, false);
+  EXPECT_FALSE(instant_ntp_prerenderer()->IsJavascriptEnabled());
+}
diff --git a/chrome/browser/ui/search/instant_page.cc b/chrome/browser/ui/search/instant_page.cc
index 39fc72c..9177352 100644
--- a/chrome/browser/ui/search/instant_page.cc
+++ b/chrome/browser/ui/search/instant_page.cc
@@ -6,6 +6,10 @@
 
 #include "apps/app_launcher.h"
 #include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/chrome_notification_types.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"
 #include "chrome/browser/ui/search/instant_tab.h"
 #include "chrome/browser/ui/search/search_model.h"
@@ -15,6 +19,8 @@
 #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/notification_service.h"
+#include "content/public/browser/notification_source.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/frame_navigate_params.h"
 #include "ui/base/resource/resource_bundle.h"
@@ -26,6 +32,13 @@
 InstantPage::~InstantPage() {
   if (contents())
     SearchTabHelper::FromWebContents(contents())->model()->RemoveObserver(this);
+
+  // |profile_| may be NULL during unit tests.
+  if (profile_) {
+    InstantService* instant_service =
+        InstantServiceFactory::GetForProfile(profile_);
+    instant_service->RemoveObserver(this);
+  }
 }
 
 bool InstantPage::supports_instant() const {
@@ -62,11 +75,18 @@
 }
 
 InstantPage::InstantPage(Delegate* delegate, const std::string& instant_url,
-                         bool is_incognito)
-    : delegate_(delegate),
+                         Profile* profile, bool is_incognito)
+    : profile_(profile),
+      delegate_(delegate),
       ipc_sender_(InstantIPCSender::Create(is_incognito)),
       instant_url_(instant_url),
       is_incognito_(is_incognito) {
+  // |profile_| may be NULL during unit tests.
+  if (profile_) {
+    InstantService* instant_service =
+        InstantServiceFactory::GetForProfile(profile_);
+    instant_service->AddObserver(this);
+  }
 }
 
 void InstantPage::SetContents(content::WebContents* web_contents) {
@@ -161,6 +181,20 @@
     delegate_->InstantPageLoadFailed(contents());
 }
 
+void InstantPage::ThemeInfoChanged(const ThemeBackgroundInfo& theme_info) {
+  sender()->SendThemeBackgroundInfo(theme_info);
+}
+
+void InstantPage::MostVisitedItemsChanged(
+    const std::vector<InstantMostVisitedItem>& items) {
+  sender()->SendMostVisitedItems(items);
+
+  content::NotificationService::current()->Notify(
+      chrome::NOTIFICATION_INSTANT_SENT_MOST_VISITED_ITEMS,
+      content::Source<InstantPage>(this),
+      content::NotificationService::NoDetails());
+}
+
 void InstantPage::ModelChanged(const SearchModel::State& old_state,
                                const SearchModel::State& new_state) {
   if (old_state.instant_support != new_state.instant_support)
diff --git a/chrome/browser/ui/search/instant_page.h b/chrome/browser/ui/search/instant_page.h
index f26e940..efd42b3 100644
--- a/chrome/browser/ui/search/instant_page.h
+++ b/chrome/browser/ui/search/instant_page.h
@@ -12,6 +12,7 @@
 #include "base/gtest_prod_util.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/strings/string16.h"
+#include "chrome/browser/search/instant_service_observer.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"
@@ -20,6 +21,8 @@
 #include "content/public/common/page_transition_types.h"
 
 class GURL;
+class InstantService;
+class Profile;
 
 namespace content {
 struct FrameNavigateParams;
@@ -36,6 +39,7 @@
 // InstantPage is not used directly but via one of its derived classes,
 // InstantNTP and InstantTab.
 class InstantPage : public content::WebContentsObserver,
+                    public InstantServiceObserver,
                     public SearchModelObserver {
  public:
   // InstantPage calls its delegate in response to messages received from the
@@ -43,19 +47,11 @@
   // we are observing.
   class Delegate {
    public:
-    // Called when a RenderView is created, so that state can be initialized.
-    virtual void InstantPageRenderViewCreated(
-        const content::WebContents* contents) = 0;
-
     // Called upon determination of Instant API support. Either in response to
     // the page loading or because we received some other message.
     virtual void InstantSupportDetermined(const content::WebContents* contents,
                                           bool supports_instant) = 0;
 
-    // Called when the underlying RenderView's process crashed.
-    virtual void InstantPageRenderProcessGone(
-        const content::WebContents* contents) = 0;
-
     // Called when the page is about to navigate to |url|.
     virtual void InstantPageAboutToNavigateMainFrame(
         const content::WebContents* contents,
@@ -120,7 +116,7 @@
 
  protected:
   InstantPage(Delegate* delegate, const std::string& instant_url,
-              bool is_incognito);
+              Profile* profile, bool is_incognito);
 
   // Sets |web_contents| as the page to communicate with. |web_contents| may be
   // NULL, which effectively stops all communication.
@@ -128,6 +124,8 @@
 
   Delegate* delegate() const { return delegate_; }
 
+  Profile* profile() const { return profile_; }
+
   // These functions are called before processing messages received from the
   // 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
@@ -172,6 +170,11 @@
       const string16& error_description,
       content::RenderViewHost* render_view_host) OVERRIDE;
 
+  // Overridden from InstantServiceObserver:
+  virtual void ThemeInfoChanged(const ThemeBackgroundInfo& theme_info) OVERRIDE;
+  virtual void MostVisitedItemsChanged(
+      const std::vector<InstantMostVisitedItem>& items) OVERRIDE;
+
   // Overridden from SearchModelObserver:
   virtual void ModelChanged(const SearchModel::State& old_state,
                             const SearchModel::State& new_state) OVERRIDE;
@@ -192,6 +195,10 @@
 
   void ClearContents();
 
+  // Returns the InstantService for the |profile_|.
+  InstantService* GetInstantService();
+
+  Profile* profile_;
   Delegate* const delegate_;
   scoped_ptr<InstantIPCSender> ipc_sender_;
   const std::string instant_url_;
diff --git a/chrome/browser/ui/search/instant_page_unittest.cc b/chrome/browser/ui/search/instant_page_unittest.cc
index e16c96d..2b1ec86 100644
--- a/chrome/browser/ui/search/instant_page_unittest.cc
+++ b/chrome/browser/ui/search/instant_page_unittest.cc
@@ -20,6 +20,8 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
 
+class Profile;
+
 namespace {
 
 class FakePageDelegate : public InstantPage::Delegate {
@@ -27,8 +29,6 @@
   virtual ~FakePageDelegate() {
   }
 
-  MOCK_METHOD1(InstantPageRenderViewCreated,
-               void(const content::WebContents* contents));
   MOCK_METHOD2(InstantSupportDetermined,
                void(const content::WebContents* contents,
                     bool supports_instant));
@@ -55,7 +55,7 @@
 class FakePage : public InstantPage {
  public:
   FakePage(Delegate* delegate, const std::string& instant_url,
-           bool is_incognito);
+           Profile* profile, bool is_incognito);
   virtual ~FakePage();
 
   // InstantPage overrride.
@@ -75,18 +75,14 @@
 };
 
 FakePage::FakePage(Delegate* delegate, const std::string& instant_url,
-                   bool is_incognito)
-    : InstantPage(delegate, instant_url, is_incognito),
+                   Profile* profile, bool is_incognito)
+    : InstantPage(delegate, instant_url, profile, is_incognito),
       should_handle_messages_(true) {
 }
 
 FakePage::~FakePage() {
 }
 
-void FakePage::set_should_handle_messages(bool should_handle_messages) {
-  should_handle_messages_ = should_handle_messages;
-}
-
 bool FakePage::ShouldProcessDeleteMostVisitedItem() {
   return should_handle_messages_;
 }
@@ -99,6 +95,10 @@
   return should_handle_messages_;
 }
 
+void FakePage::set_should_handle_messages(bool should_handle_messages) {
+  should_handle_messages_ = should_handle_messages;
+}
+
 }  // namespace
 
 class InstantPageTest : public ChromeRenderViewHostTestHarness {
@@ -121,7 +121,7 @@
 }
 
 TEST_F(InstantPageTest, IsLocal) {
-  page.reset(new FakePage(&delegate, "", false));
+  page.reset(new FakePage(&delegate, "", NULL, false));
   EXPECT_FALSE(page->supports_instant());
   EXPECT_FALSE(page->IsLocal());
   page->SetContents(web_contents());
@@ -132,7 +132,7 @@
 }
 
 TEST_F(InstantPageTest, DetermineIfPageSupportsInstant_Local) {
-  page.reset(new FakePage(&delegate, "", false));
+  page.reset(new FakePage(&delegate, "", NULL, false));
   EXPECT_FALSE(page->supports_instant());
   page->SetContents(web_contents());
   NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl));
@@ -145,7 +145,7 @@
 }
 
 TEST_F(InstantPageTest, DetermineIfPageSupportsInstant_NonLocal) {
-  page.reset(new FakePage(&delegate, "", false));
+  page.reset(new FakePage(&delegate, "", NULL, false));
   EXPECT_FALSE(page->supports_instant());
   page->SetContents(web_contents());
   NavigateAndCommit(GURL("chrome-search://foo/bar"));
@@ -160,7 +160,7 @@
 }
 
 TEST_F(InstantPageTest, DispatchRequestToDeleteMostVisitedItem) {
-  page.reset(new FakePage(&delegate, "", false));
+  page.reset(new FakePage(&delegate, "", NULL, false));
   page->SetContents(web_contents());
   NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl));
   GURL item_url("www.foo.com");
@@ -172,7 +172,7 @@
 }
 
 TEST_F(InstantPageTest, DispatchRequestToUndoMostVisitedDeletion) {
-  page.reset(new FakePage(&delegate, "", false));
+  page.reset(new FakePage(&delegate, "", NULL, false));
   page->SetContents(web_contents());
   NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl));
   GURL item_url("www.foo.com");
@@ -184,7 +184,7 @@
 }
 
 TEST_F(InstantPageTest, DispatchRequestToUndoAllMostVisitedDeletions) {
-  page.reset(new FakePage(&delegate, "", false));
+  page.reset(new FakePage(&delegate, "", NULL, false));
   page->SetContents(web_contents());
   NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl));
   int page_id = web_contents()->GetController().GetActiveEntry()->GetPageID();
@@ -195,7 +195,7 @@
 }
 
 TEST_F(InstantPageTest, IgnoreMessageReceivedFromIncognitoPage) {
-  page.reset(new FakePage(&delegate, "", true));
+  page.reset(new FakePage(&delegate, "", NULL, true));
   page->SetContents(web_contents());
   NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl));
   GURL item_url("www.foo.com");
@@ -220,7 +220,7 @@
 }
 
 TEST_F(InstantPageTest, IgnoreMessageIfThePageIsNotActive) {
-  page.reset(new FakePage(&delegate, "", false));
+  page.reset(new FakePage(&delegate, "", NULL, false));
   page->SetContents(web_contents());
   NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl));
   GURL item_url("www.foo.com");
@@ -245,7 +245,7 @@
 }
 
 TEST_F(InstantPageTest, IgnoreMessageReceivedFromThePage) {
-  page.reset(new FakePage(&delegate, "", false));
+  page.reset(new FakePage(&delegate, "", NULL, false));
   page->SetContents(web_contents());
 
   // Ignore the messages received from the page.
@@ -271,7 +271,7 @@
 }
 
 TEST_F(InstantPageTest, PageURLDoesntBelongToInstantRenderer) {
-  page.reset(new FakePage(&delegate, "", false));
+  page.reset(new FakePage(&delegate, "", NULL, false));
   EXPECT_FALSE(page->supports_instant());
   NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl));
   page->SetContents(web_contents());
@@ -296,7 +296,7 @@
 // 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));
+  page.reset(new FakePage(&delegate, "", NULL, false));
   EXPECT_FALSE(page->supports_instant());
   page->SetContents(web_contents());
   NavigateAndCommit(GURL("chrome-search://foo/bar"));
@@ -322,7 +322,7 @@
 }
 
 TEST_F(InstantPageTest, AppropriateMessagesSentToIncognitoPages) {
-  page.reset(new FakePage(&delegate, "", true));
+  page.reset(new FakePage(&delegate, "", NULL, true));
   page->SetContents(web_contents());
   NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl));
   process()->sink().ClearMessages();
diff --git a/chrome/browser/ui/search/instant_tab.cc b/chrome/browser/ui/search/instant_tab.cc
index ff54979..ef2500d 100644
--- a/chrome/browser/ui/search/instant_tab.cc
+++ b/chrome/browser/ui/search/instant_tab.cc
@@ -3,12 +3,14 @@
 // found in the LICENSE file.
 
 #include "chrome/browser/ui/search/instant_tab.h"
+
+#include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/webui/ntp/ntp_user_data_logger.h"
 #include "content/public/browser/web_contents.h"
 
 InstantTab::InstantTab(InstantPage::Delegate* delegate,
-                       bool is_incognito)
-    : InstantPage(delegate, "", is_incognito) {
+                       Profile* profile)
+    : InstantPage(delegate, "", profile, profile->IsOffTheRecord()) {
 }
 
 InstantTab::~InstantTab() {
diff --git a/chrome/browser/ui/search/instant_tab.h b/chrome/browser/ui/search/instant_tab.h
index 14e065e..2aac53d 100644
--- a/chrome/browser/ui/search/instant_tab.h
+++ b/chrome/browser/ui/search/instant_tab.h
@@ -9,11 +9,13 @@
 #include "base/compiler_specific.h"
 #include "chrome/browser/ui/search/instant_page.h"
 
+class Profile;
+
 // InstantTab represents a committed page (i.e. an actual tab on the tab strip)
 // that supports the Instant API.
 class InstantTab : public InstantPage {
  public:
-  InstantTab(InstantPage::Delegate* delegate, bool is_incognito);
+  InstantTab(InstantPage::Delegate* delegate, Profile* profile);
   virtual ~InstantTab();
 
   // Start observing |contents| for messages. Sends a message to determine if
diff --git a/chrome/browser/ui/search/instant_test_utils.cc b/chrome/browser/ui/search/instant_test_utils.cc
index 5c94421..50eb25c 100644
--- a/chrome/browser/ui/search/instant_test_utils.cc
+++ b/chrome/browser/ui/search/instant_test_utils.cc
@@ -9,10 +9,13 @@
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/chrome_notification_types.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_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_ntp_prerenderer.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/interactive_test_utils.h"
@@ -52,7 +55,10 @@
   service->Add(template_url);  // Takes ownership of |template_url|.
   service->SetDefaultSearchProvider(template_url);
 
-  instant()->ReloadStaleNTP();
+  InstantService* instant_service =
+      InstantServiceFactory::GetForProfile(browser_->profile());
+  ASSERT_NE(static_cast<InstantService*>(NULL), instant_service);
+  instant_service->ntp_prerenderer()->ReloadStaleNTP();
 }
 
 void InstantTestBase::SetInstantURL(const std::string& url) {
@@ -88,7 +94,12 @@
       chrome::NOTIFICATION_INSTANT_NTP_SUPPORT_DETERMINED,
       content::NotificationService::AllSources());
   FocusOmnibox();
-  if (!instant()->ntp() || !instant()->ntp()->supports_instant())
+
+  InstantService* instant_service =
+      InstantServiceFactory::GetForProfile(browser_->profile());
+  ASSERT_NE(static_cast<InstantService*>(NULL), instant_service);
+  if (!instant_service->ntp_prerenderer()->ntp() ||
+      !instant_service->ntp_prerenderer()->ntp()->supports_instant())
     ntp_observer.Wait();
 }
 
@@ -127,7 +138,11 @@
 }
 
 bool InstantTestBase::ExecuteScript(const std::string& script) {
-  return content::ExecuteScript(instant()->GetNTPContents(), script);
+  InstantService* instant_service =
+      InstantServiceFactory::GetForProfile(browser_instant()->profile());
+  if (!instant_service)
+    return false;
+  return content::ExecuteScript(instant_service->GetNTPContents(), script);
 }
 
 bool InstantTestBase::CheckVisibilityIs(content::WebContents* contents,
diff --git a/chrome/browser/ui/search/search_model.cc b/chrome/browser/ui/search/search_model.cc
index 694f456..fac64e6 100644
--- a/chrome/browser/ui/search/search_model.cc
+++ b/chrome/browser/ui/search/search_model.cc
@@ -8,24 +8,20 @@
 #include "chrome/browser/ui/search/search_model_observer.h"
 
 SearchModel::State::State()
-    : top_bars_visible(true),
-      instant_support(INSTANT_SUPPORT_UNKNOWN),
+    : 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 &&
+  return mode == rhs.mode && instant_support == rhs.instant_support &&
       voice_search_supported == rhs.voice_search_supported;
 }
 
@@ -61,27 +57,6 @@
   const State old_state = state_;
   state_.mode = new_mode;
 
-  // For |SEARCH_SUGGESTIONS| and |SEARCH_RESULTS| modes, SearchBox API will
-  // determine visibility of top bars via SetTopBarsVisible(); for other modes,
-  // top bars are always visible, if available.
-  if (!state_.mode.is_search())
-    state_.top_bars_visible = true;
-
-  FOR_EACH_OBSERVER(SearchModelObserver, observers_,
-                    ModelChanged(old_state, state_));
-}
-
-void SearchModel::SetTopBarsVisible(bool visible) {
-  DCHECK(chrome::IsInstantExtendedAPIEnabled())
-      << "Please do not try to set the SearchModel state without first "
-      << "checking if Search is enabled.";
-
-  if (state_.top_bars_visible == visible)
-    return;
-
-  const State old_state = state_;
-  state_.top_bars_visible = visible;
-
   FOR_EACH_OBSERVER(SearchModelObserver, observers_,
                     ModelChanged(old_state, state_));
 }
diff --git a/chrome/browser/ui/search/search_model.h b/chrome/browser/ui/search/search_model.h
index 3ddb58e..dfbdf4f 100644
--- a/chrome/browser/ui/search/search_model.h
+++ b/chrome/browser/ui/search/search_model.h
@@ -25,7 +25,6 @@
   struct State {
     State();
     State(const SearchMode& mode,
-          bool top_bars_visible,
           InstantSupportState instant_support,
           bool voice_search_supported);
 
@@ -34,9 +33,6 @@
     // 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;
 
@@ -59,12 +55,6 @@
   // Get the active mode.
   const SearchMode& mode() const { return state_.mode; }
 
-  // Set visibility of top bars.  Change notifications are sent to observers.
-  void SetTopBarsVisible(bool visible);
-
-  // 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);
diff --git a/chrome/browser/ui/search/search_model_unittest.cc b/chrome/browser/ui/search/search_model_unittest.cc
index 762256b..a1d0365 100644
--- a/chrome/browser/ui/search/search_model_unittest.cc
+++ b/chrome/browser/ui/search/search_model_unittest.cc
@@ -135,23 +135,8 @@
   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);
diff --git a/chrome/browser/ui/search/search_tab_helper.cc b/chrome/browser/ui/search/search_tab_helper.cc
index 281667f..8b6dee9 100644
--- a/chrome/browser/ui/search/search_tab_helper.cc
+++ b/chrome/browser/ui/search/search_tab_helper.cc
@@ -205,7 +205,6 @@
     // OmniboxEditModel::SetInputInProgress() which is called from
     // OmniboxEditModel::Revert().
     model_.SetState(SearchModel::State(SearchMode(type, origin),
-                                       model_.state().top_bars_visible,
                                        model_.instant_support(),
                                        model_.state().voice_search_supported));
   } else {
diff --git a/chrome/browser/ui/startup/autolaunch_prompt_win.cc b/chrome/browser/ui/startup/autolaunch_prompt_win.cc
index 0671954..4471fca 100644
--- a/chrome/browser/ui/startup/autolaunch_prompt_win.cc
+++ b/chrome/browser/ui/startup/autolaunch_prompt_win.cc
@@ -36,7 +36,7 @@
 // The delegate for the infobar shown when Chrome is auto-launched.
 class AutolaunchInfoBarDelegate : public ConfirmInfoBarDelegate {
  public:
-  // Creates an autolaunch delegate and adds it to |infobar_service|.
+  // Creates an autolaunch infobar delegate and adds it to |infobar_service|.
   static void Create(InfoBarService* infobar_service, Profile* profile);
 
  private:
diff --git a/chrome/browser/ui/startup/bad_flags_prompt.cc b/chrome/browser/ui/startup/bad_flags_prompt.cc
index 71c977a..f8bbea9 100644
--- a/chrome/browser/ui/startup/bad_flags_prompt.cc
+++ b/chrome/browser/ui/startup/bad_flags_prompt.cc
@@ -11,6 +11,7 @@
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/common/chrome_switches.h"
+#include "extensions/common/switches.h"
 #include "grit/generated_resources.h"
 #include "ui/base/l10n/l10n_util.h"
 
@@ -32,7 +33,7 @@
     // Browser plugin is dangerous on regular pages because it breaks the Same
     // Origin Policy.
     switches::kEnableBrowserPluginForAllViewTypes,
-    switches::kExtensionsOnChromeURLs,
+    extensions::switches::kExtensionsOnChromeURLs,
     // This parameter should be used only for server side developments.
     switches::kTranslateScriptURL,
     NULL
@@ -44,9 +45,8 @@
           InfoBarService::FromWebContents(web_contents),
           InfoBarDelegate::kNoIconID,
           l10n_util::GetStringFUTF16(IDS_BAD_FLAGS_WARNING_MESSAGE,
-                                      UTF8ToUTF16(std::string("--") + *flag)),
+                                     UTF8ToUTF16(std::string("--") + *flag)),
           false);
-
       return;
     }
   }
diff --git a/chrome/browser/ui/startup/default_browser_prompt.cc b/chrome/browser/ui/startup/default_browser_prompt.cc
index 4550195..786dcad 100644
--- a/chrome/browser/ui/startup/default_browser_prompt.cc
+++ b/chrome/browser/ui/startup/default_browser_prompt.cc
@@ -58,7 +58,8 @@
 // The delegate for the infobar shown when Chrome is not the default browser.
 class DefaultBrowserInfoBarDelegate : public ConfirmInfoBarDelegate {
  public:
-  // Creates a default browser delegate and adds it to |infobar_service|.
+  // Creates a default browser infobar delegate and adds it to
+  // |infobar_service|.
   static void Create(InfoBarService* infobar_service,
                      PrefService* prefs,
                      bool interactive_flow_required);
diff --git a/chrome/browser/ui/startup/obsolete_os_infobar_delegate.h b/chrome/browser/ui/startup/obsolete_os_infobar_delegate.h
index eedaac9..058ec48 100644
--- a/chrome/browser/ui/startup/obsolete_os_infobar_delegate.h
+++ b/chrome/browser/ui/startup/obsolete_os_infobar_delegate.h
@@ -16,7 +16,7 @@
 // a "Learn More" link.
 class ObsoleteOSInfoBarDelegate : public ConfirmInfoBarDelegate {
  public:
-  // Creates an obsolete OS delegate and adds it to |infobar_service|.
+  // Creates an obsolete OS infobar delegate and adds it to |infobar_service|.
   static void Create(InfoBarService* infobar_service);
 
  private:
diff --git a/chrome/browser/ui/startup/session_crashed_prompt.cc b/chrome/browser/ui/startup/session_crashed_infobar_delegate.cc
similarity index 80%
rename from chrome/browser/ui/startup/session_crashed_prompt.cc
rename to chrome/browser/ui/startup/session_crashed_infobar_delegate.cc
index d504839..b5a68b6 100644
--- a/chrome/browser/ui/startup/session_crashed_prompt.cc
+++ b/chrome/browser/ui/startup/session_crashed_infobar_delegate.cc
@@ -2,10 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/ui/startup/session_crashed_prompt.h"
+#include "chrome/browser/ui/startup/session_crashed_infobar_delegate.h"
 
 #include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/infobars/infobar_service.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/search/search.h"
 #include "chrome/browser/sessions/session_restore.h"
@@ -16,7 +15,6 @@
 #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/browser/web_contents.h"
 #include "grit/chromium_strings.h"
 #include "grit/generated_resources.h"
 #include "grit/theme_resources.h"
@@ -25,30 +23,29 @@
 
 // static
 void SessionCrashedInfoBarDelegate::Create(Browser* browser) {
-  // Assume that if the user is launching incognito they were previously
-  // running incognito so that we have nothing to restore from.
-  if (browser->profile()->IsOffTheRecord())
-    return;
-
-  // In ChromeBot tests, there might be a race. This line appears to get
-  // called during shutdown and |web_contents| can be NULL.
-  content::WebContents* tab =
+  // Assume that if the user is launching incognito they were previously running
+  // incognito so that we have nothing to restore from.
+  // Also, in ChromeBot tests, there might be a race.  This code appears to be
+  // called during shutdown when there is no active WebContents.
+  Profile* profile = browser->profile();
+  content::WebContents* web_contents =
       browser->tab_strip_model()->GetActiveWebContents();
-  if (!tab)
+  if (profile->IsOffTheRecord() || !web_contents)
     return;
 
-  InfoBarService* infobar_service = InfoBarService::FromWebContents(tab);
+  InfoBarService* infobar_service =
+      InfoBarService::FromWebContents(web_contents);
   infobar_service->AddInfoBar(scoped_ptr<InfoBarDelegate>(
-      new SessionCrashedInfoBarDelegate(infobar_service, browser)));
+      new SessionCrashedInfoBarDelegate(infobar_service, profile)));
 }
 
 SessionCrashedInfoBarDelegate::SessionCrashedInfoBarDelegate(
     InfoBarService* infobar_service,
-    Browser* browser)
+    Profile* profile)
     : ConfirmInfoBarDelegate(infobar_service),
       accepted_(false),
       removed_notification_received_(false),
-      profile_(browser->profile()) {
+      profile_(profile) {
   // TODO(pkasting,marja): Once InfoBars own they delegates, this is not needed
   // any more. Then we can rely on delegates getting destroyed, and we can
   // initiate the session storage scavenging only in the destructor. (Currently,
@@ -61,8 +58,8 @@
   // If the info bar wasn't accepted, it was either dismissed or expired. In
   // that case, session restore won't happen.
   if (!accepted_ && !removed_notification_received_) {
-    content::BrowserContext::GetDefaultStoragePartition(profile_)
-        ->GetDOMStorageContext()->StartScavengingUnusedSessionStorage();
+    content::BrowserContext::GetDefaultStoragePartition(profile_)->
+        GetDOMStorageContext()->StartScavengingUnusedSessionStorage();
   }
 }
 
@@ -98,9 +95,9 @@
       behavior = SessionRestore::CLOBBER_CURRENT_TAB;
     }
   }
-  SessionRestore::RestoreSession(
-      browser->profile(), browser, browser->host_desktop_type(), behavior,
-      std::vector<GURL>());
+  SessionRestore::RestoreSession(browser->profile(), browser,
+                                 browser->host_desktop_type(), behavior,
+                                 std::vector<GURL>());
   accepted_ = true;
   return true;
 }
diff --git a/chrome/browser/ui/startup/session_crashed_prompt.h b/chrome/browser/ui/startup/session_crashed_infobar_delegate.h
similarity index 81%
rename from chrome/browser/ui/startup/session_crashed_prompt.h
rename to chrome/browser/ui/startup/session_crashed_infobar_delegate.h
index a10f4d3..e842d5d 100644
--- a/chrome/browser/ui/startup/session_crashed_prompt.h
+++ b/chrome/browser/ui/startup/session_crashed_infobar_delegate.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_UI_STARTUP_SESSION_CRASHED_PROMPT_H_
-#define CHROME_BROWSER_UI_STARTUP_SESSION_CRASHED_PROMPT_H_
+#ifndef CHROME_BROWSER_UI_STARTUP_SESSION_CRASHED_INFOBAR_DELEGATE_H_
+#define CHROME_BROWSER_UI_STARTUP_SESSION_CRASHED_INFOBAR_DELEGATE_H_
 
 #include "base/gtest_prod_util.h"
 #include "base/memory/scoped_ptr.h"
@@ -18,8 +18,8 @@
 class SessionCrashedInfoBarDelegate : public ConfirmInfoBarDelegate,
                                       public content::NotificationObserver {
  public:
-  // If |browser| is not incognito, creates a session crashed delegate and adds
-  // it to the InfoBarService for |browser|.
+  // If |browser| is not incognito, creates a session crashed infobar delegate
+  // and adds it to the InfoBarService for |browser|.
   static void Create(Browser* browser);
 
  private:
@@ -30,7 +30,7 @@
 #endif
 
   SessionCrashedInfoBarDelegate(InfoBarService* infobar_service,
-                                Browser* browser);
+                                Profile* profile);
   virtual ~SessionCrashedInfoBarDelegate();
 
   // ConfirmInfoBarDelegate:
@@ -53,4 +53,4 @@
   DISALLOW_COPY_AND_ASSIGN(SessionCrashedInfoBarDelegate);
 };
 
-#endif  // CHROME_BROWSER_UI_STARTUP_SESSION_CRASHED_PROMPT_H_
+#endif  // CHROME_BROWSER_UI_STARTUP_SESSION_CRASHED_INFOBAR_DELEGATE_H_
diff --git a/chrome/browser/ui/startup/session_crashed_infobar_delegate_unittest.cc b/chrome/browser/ui/startup/session_crashed_infobar_delegate_unittest.cc
index f9bcfe4..473928d 100644
--- a/chrome/browser/ui/startup/session_crashed_infobar_delegate_unittest.cc
+++ b/chrome/browser/ui/startup/session_crashed_infobar_delegate_unittest.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/ui/startup/session_crashed_infobar_delegate.h"
+
 #include "base/prefs/pref_registry_simple.h"
 #include "base/prefs/testing_pref_service.h"
 #include "base/run_loop.h"
 #include "chrome/browser/infobars/infobar_service.h"
 #include "chrome/browser/sessions/session_service_factory.h"
-#include "chrome/browser/ui/startup/session_crashed_prompt.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/url_constants.h"
@@ -60,9 +61,9 @@
   InfoBarService* infobar_service =
       InfoBarService::FromWebContents(web_contents);
   EXPECT_EQ(1U, infobar_service->infobar_count());
-  scoped_ptr<SessionCrashedInfoBarDelegate> info_bar(
-      reinterpret_cast<SessionCrashedInfoBarDelegate*>(
-          InfoBarService::FromWebContents(web_contents)->infobar_at(0)));
+  scoped_ptr<ConfirmInfoBarDelegate> infobar(InfoBarService::FromWebContents(
+      web_contents)->infobar_at(0)->AsConfirmInfoBarDelegate());
+  ASSERT_TRUE(infobar);
 
   // Open another browser.
   scoped_ptr<Browser> opened_browser(
@@ -83,7 +84,7 @@
   EXPECT_EQ(1U, infobar_service->infobar_count());
 
   // This used to crash.
-  info_bar->Accept();
+  infobar->Accept();
 
   // Ramp down the test.
   tab_strip->CloseWebContentsAt(0, TabStripModel::CLOSE_NONE);
diff --git a/chrome/browser/ui/startup/startup_browser_creator_impl.cc b/chrome/browser/ui/startup/startup_browser_creator_impl.cc
index 0b09eba..c26ac9d 100644
--- a/chrome/browser/ui/startup/startup_browser_creator_impl.cc
+++ b/chrome/browser/ui/startup/startup_browser_creator_impl.cc
@@ -64,7 +64,7 @@
 #include "chrome/browser/ui/startup/default_browser_prompt.h"
 #include "chrome/browser/ui/startup/google_api_keys_infobar_delegate.h"
 #include "chrome/browser/ui/startup/obsolete_os_infobar_delegate.h"
-#include "chrome/browser/ui/startup/session_crashed_prompt.h"
+#include "chrome/browser/ui/startup/session_crashed_infobar_delegate.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"
@@ -357,7 +357,7 @@
   AppListService::InitAll(profile);
   if (command_line_.HasSwitch(switches::kShowAppList)) {
     AppListService::RecordShowTimings(command_line_);
-    AppListService::Get()->ShowAppList(profile);
+    AppListService::Get()->ShowForProfile(profile);
     return true;
   }
 
diff --git a/chrome/browser/ui/sync/one_click_signin_helper.cc b/chrome/browser/ui/sync/one_click_signin_helper.cc
index 992b88a..0fd124a 100644
--- a/chrome/browser/ui/sync/one_click_signin_helper.cc
+++ b/chrome/browser/ui/sync/one_click_signin_helper.cc
@@ -25,7 +25,6 @@
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/defaults.h"
 #include "chrome/browser/google/google_util.h"
-#include "chrome/browser/infobars/infobar_service.h"
 #include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_info_cache.h"
@@ -33,6 +32,7 @@
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/search/search.h"
 #include "chrome/browser/signin/chrome_signin_manager_delegate.h"
+#include "chrome/browser/signin/signin_global_error.h"
 #include "chrome/browser/signin/signin_manager.h"
 #include "chrome/browser/signin/signin_manager_delegate.h"
 #include "chrome/browser/signin/signin_manager_factory.h"
@@ -49,6 +49,7 @@
 #include "chrome/browser/ui/sync/signin_histogram.h"
 #include "chrome/browser/ui/tab_modal_confirm_dialog.h"
 #include "chrome/browser/ui/tab_modal_confirm_dialog_delegate.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/chrome_version_info.h"
 #include "chrome/common/net/url_util.h"
@@ -180,8 +181,15 @@
       UMA_HISTOGRAM_ENUMERATION("Signin.AppsPageLinkActions", action,
                                 one_click_signin::HISTOGRAM_MAX);
       break;
+    case SyncPromoUI::SOURCE_BOOKMARK_BUBBLE:
+      UMA_HISTOGRAM_ENUMERATION("Signin.BookmarkBubbleActions", action,
+                                one_click_signin::HISTOGRAM_MAX);
+      break;
     default:
-      NOTREACHED() << "Invalid Source";
+      // This switch statement needs to be updated when the enum Source changes.
+      COMPILE_ASSERT(SyncPromoUI::SOURCE_UNKNOWN == 9,
+                     kSourceEnumHasChangedButNotThisSwitchStatement);
+      NOTREACHED();
       return;
   }
   UMA_HISTOGRAM_ENUMERATION("Signin.AllAccessPointActions", action,
@@ -415,8 +423,7 @@
     const std::string& last_email,
     const std::string& email,
     Callback callback)
-  : TabModalConfirmDialogDelegate(contents),
-    last_email_(last_email),
+  : last_email_(last_email),
     email_(email),
     callback_(callback) {
 }
@@ -503,6 +510,20 @@
   delete this;  // Failure.
 }
 
+void CloseTab(content::WebContents* tab) {
+  Browser* browser = chrome::FindBrowserWithWebContents(tab);
+  if (browser) {
+    TabStripModel* tab_strip_model = browser->tab_strip_model();
+    if (tab_strip_model) {
+      int index = tab_strip_model->GetIndexOfWebContents(tab);
+      if (index != TabStripModel::kNoTab) {
+        tab_strip_model->ExecuteContextMenuCommand(
+            index, TabStripModel::CommandCloseTab);
+      }
+    }
+  }
+}
+
 }  // namespace
 
 
@@ -1120,6 +1141,11 @@
       return;
     }
 
+    // Initialize |original_source_| if this is the first time the page has
+    // finished loading.
+    if (original_source_ == SyncPromoUI::SOURCE_UNKNOWN)
+      original_source_ = source_;
+
     // In explicit sign ins, the user may have changed the box
     // "Let me choose what to sync".  This is reflected as a change in the
     // source of the continue URL.  Make one last check of the current URL
@@ -1184,9 +1210,18 @@
         LogHistogramValue(source_, one_click_signin::HISTOGRAM_ACCEPTED);
         LogHistogramValue(source_, one_click_signin::HISTOGRAM_WITH_DEFAULTS);
       }
+
+      // - If sign in was initiated from the NTP or the hotdog menu, sync with
+      //   default settings.
+      // - If sign in was initiated from the settings page for first time sync
+      //   set up, show the advanced sync settings dialog.
+      // - If sign in was initiated from the settings page due to a re-auth,
+      //   simply navigate back to the settings page.
       OneClickSigninSyncStarter::StartSyncMode start_mode =
           source_ == SyncPromoUI::SOURCE_SETTINGS ?
-              OneClickSigninSyncStarter::CONFIGURE_SYNC_FIRST :
+              SigninGlobalError::GetForProfile(profile)->HasMenuItem() ?
+                  OneClickSigninSyncStarter::SHOW_SETTINGS_WITHOUT_CONFIGURE :
+                  OneClickSigninSyncStarter::CONFIGURE_SYNC_FIRST :
               OneClickSigninSyncStarter::SYNC_WITH_DEFAULT_SETTINGS;
 
       std::string last_email =
@@ -1219,17 +1254,21 @@
 
         // If this explicit sign in is not from settings page/webstore, show
         // the NTP/Apps page after sign in completes. In the case of the
-        // settings page, it will get closed by SyncSetupHandler. In the case
+        // settings page, it will get auto-closed after sync setup. In the case
         // of webstore, it will redirect back to webstore.
         RedirectToNtpOrAppsPageIfNecessary(web_contents(), source_);
       }
 
-      if (source_ == SyncPromoUI::SOURCE_SETTINGS &&
-          SyncPromoUI::GetSourceForSyncPromoURL(continue_url_) ==
-          SyncPromoUI::SOURCE_WEBSTORE_INSTALL) {
+      // Observe the sync service if the Webstore tab or the settings tab
+      // requested a gaia sign in, so that when sign in and sync setup are
+      // successful, we can redirect to the correct URL, or auto-close the gaia
+      // sign in tab.
+      if (original_source_ == SyncPromoUI::SOURCE_SETTINGS ||
+          (original_source_ == SyncPromoUI::SOURCE_WEBSTORE_INSTALL &&
+           source_ == SyncPromoUI::SOURCE_SETTINGS)) {
         redirect_url_ = continue_url_;
         ProfileSyncService* sync_service =
-          ProfileSyncServiceFactory::GetForProfile(profile);
+            ProfileSyncServiceFactory::GetForProfile(profile);
         if (sync_service)
           sync_service->AddObserver(this);
       }
@@ -1259,15 +1298,27 @@
   ProfileSyncService* sync_service =
       ProfileSyncServiceFactory::GetForProfile(profile);
 
-  // Sync setup not completed yet.
-  if (sync_service->FirstSetupInProgress())
-    return;
+  // At this point, the sign in process is complete, and control has been handed
+  // back to the sync engine. Close the gaia sign in tab if |redirect_url_|
+  // contains the |auto_close| parameter. Otherwise, wait for sync setup to
+  // complete and then navigate to |redirect_url_|.
+  if (SyncPromoUI::IsAutoCloseEnabledInURL(redirect_url_)) {
+    // Close the gaia sign in tab via a task to make sure we aren't in the
+    // middle of any webui handler code.
+    base::MessageLoop::current()->PostTask(
+        FROM_HERE,
+        base::Bind(&CloseTab, base::Unretained(contents)));
+  } else {
+    // Sync setup not completed yet.
+    if (sync_service->FirstSetupInProgress())
+      return;
 
-  if (sync_service->sync_initialized()) {
-    contents->GetController().LoadURL(redirect_url_,
-                                      content::Referrer(),
-                                      content::PAGE_TRANSITION_AUTO_TOPLEVEL,
-                                      std::string());
+    if (sync_service->sync_initialized()) {
+      contents->GetController().LoadURL(redirect_url_,
+                                        content::Referrer(),
+                                        content::PAGE_TRANSITION_AUTO_TOPLEVEL,
+                                        std::string());
+    }
   }
 
   // Clear the redirect URL.
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 e26356b..d5c232a 100644
--- a/chrome/browser/ui/sync/one_click_signin_sync_starter.cc
+++ b/chrome/browser/ui/sync/one_click_signin_sync_starter.cc
@@ -357,9 +357,23 @@
 }
 
 void OneClickSigninSyncStarter::SigninSuccess() {
+  // Before handing control back to sync setup, update the auth error state of
+  // ProfileSyncService if needed. This is necessary because ProfileSyncService
+  // will normally update its auth error state only after attempting a sync
+  // cycle, and we do not want old auth errors to remain visible on the menu or
+  // the settings page.
+  // TODO(rsimha): We shouldn't have to do this here. PSS must update its auth
+  // state after the backend is inititialized if it waiting_for_auth() is true.
+  ProfileSyncService* profile_sync_service = GetProfileSyncService();
+  if (profile_sync_service &&
+      profile_sync_service->GetAuthError().state() !=
+          GoogleServiceAuthError::NONE) {
+    profile_sync_service->UpdateAuthErrorState(
+        GoogleServiceAuthError::AuthErrorNone());
+  }
+
   switch (start_mode_) {
     case SYNC_WITH_DEFAULT_SETTINGS: {
-      ProfileSyncService* profile_sync_service = GetProfileSyncService();
       // Just kick off the sync machine, no need to configure it first.
       if (profile_sync_service)
         profile_sync_service->SetSyncSetupCompleted();
@@ -376,7 +390,10 @@
       break;
     }
     case CONFIGURE_SYNC_FIRST:
-      ConfigureSync();
+      ShowSettingsPageInNewTab(true);  // Show sync config UI.
+      break;
+    case SHOW_SETTINGS_WITHOUT_CONFIGURE:
+      ShowSettingsPageInNewTab(false);  // Don't show sync config UI.
       break;
     default:
       NOTREACHED();
@@ -410,7 +427,7 @@
   }
 }
 
-void OneClickSigninSyncStarter::ConfigureSync() {
+void OneClickSigninSyncStarter::ShowSettingsPageInNewTab(bool configure_sync) {
   // Give the user a chance to configure things. We don't clear the
   // ProfileSyncService::setup_in_progress flag because we don't want sync
   // to start up until after the configure UI is displayed (the configure UI
@@ -426,7 +443,15 @@
       if (force_same_tab_navigation_) {
         ShowSyncSettingsPageOnSameTab();
       } else {
-        chrome::ShowSettingsSubPage(browser_, chrome::kSyncSetupSubPage);
+        // If the user is setting up sync for the first time, let them configure
+        // advanced sync settings. However, in the case of re-authentication,
+        // return the user to the settings page without showing any config UI.
+        if (configure_sync) {
+          chrome::ShowSettingsSubPage(browser_, chrome::kSyncSetupSubPage);
+        } else {
+          FinishProfileSyncServiceSetup();
+          chrome::ShowSettings(browser_);
+        }
       }
     } else {
       // Sync is disabled - just display the settings page.
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 ce4ccda..0bbe183 100644
--- a/chrome/browser/ui/sync/one_click_signin_sync_starter.h
+++ b/chrome/browser/ui/sync/one_click_signin_sync_starter.h
@@ -38,6 +38,11 @@
     // to configure which data types to sync before sync is enabled.
     CONFIGURE_SYNC_FIRST,
 
+    // Starts the process of re-authenticating the user via SigninManager,
+    // and once completed, redirects the user to the settings page, but doesn't
+    // display the configure sync UI.
+    SHOW_SETTINGS_WITHOUT_CONFIGURE,
+
     // The process should be aborted because the undo button has been pressed.
     UNDO_SYNC
   };
@@ -147,8 +152,11 @@
 
   void FinishProfileSyncServiceSetup();
 
-  // Displays the sync configuration UI.
-  void ConfigureSync();
+  // Displays the settings UI in a new tab. Brings up the advanced sync settings
+  // dialog if |configure_sync| is true.
+  void ShowSettingsPageInNewTab(bool configure_sync);
+
+  // Displays the sync configuration UI in the same tab.
   void ShowSyncSettingsPageOnSameTab();
 
   // Shows the post-signin confirmation bubble. If |custom_message| is empty,
diff --git a/chrome/browser/ui/sync/sync_promo_ui.cc b/chrome/browser/ui/sync/sync_promo_ui.cc
index 8698f14..15a597c 100644
--- a/chrome/browser/ui/sync/sync_promo_ui.cc
+++ b/chrome/browser/ui/sync/sync_promo_ui.cc
@@ -97,10 +97,6 @@
   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;
@@ -143,6 +139,10 @@
                                                bool is_new_profile) {
   DCHECK(profile);
 
+  // Don't show if the profile is an incognito.
+  if (profile->IsOffTheRecord())
+    return false;
+
   if (!ShouldShowSyncPromo(profile))
     return false;
 
@@ -224,12 +224,16 @@
   // 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.
+  // It is also parsed for the |auto_close| flag, which indicates that the tab
+  // must be closed after sync setup is successful.
   // 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));
+  if (auto_close)
+    base::StringAppendF(&continue_url, "&%s=1", kSyncPromoQueryKeyAutoClose);
 
   base::StringAppendF(&url_string, "&%s=%s", kSyncPromoQueryKeyContinue,
                       net::EscapeQueryParamValue(
@@ -261,6 +265,17 @@
 }
 
 // static
+bool SyncPromoUI::IsAutoCloseEnabledInURL(const GURL& url) {
+  std::string value;
+  if (net::GetValueForKeyInQuery(url, kSyncPromoQueryKeyAutoClose, &value)) {
+    int enabled = 0;
+    if (base::StringToInt(value, &enabled) && enabled == 1)
+      return true;
+  }
+  return false;
+}
+
+// static
 bool SyncPromoUI::IsContinueUrlForWebBasedSigninFlow(const GURL& url) {
   GURL::Replacements replacements;
   replacements.ClearQuery();
diff --git a/chrome/browser/ui/sync/sync_promo_ui.h b/chrome/browser/ui/sync/sync_promo_ui.h
index 12b04b5..46fa449 100644
--- a/chrome/browser/ui/sync/sync_promo_ui.h
+++ b/chrome/browser/ui/sync/sync_promo_ui.h
@@ -29,6 +29,7 @@
     SOURCE_WEBSTORE_INSTALL,
     SOURCE_APP_LAUNCHER,
     SOURCE_APPS_PAGE_LINK,
+    SOURCE_BOOKMARK_BUBBLE,
     SOURCE_UNKNOWN, // This must be last.
   };
 
@@ -72,6 +73,9 @@
   // The source identifies from where the sync promo was opened.
   static Source GetSourceForSyncPromoURL(const GURL& url);
 
+  // Returns true if the auto_close parameter in the given URL is set to true.
+  static bool IsAutoCloseEnabledInURL(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.
diff --git a/chrome/browser/ui/tab_contents/core_tab_helper.cc b/chrome/browser/ui/tab_contents/core_tab_helper.cc
index 52106b8..169e23a 100644
--- a/chrome/browser/ui/tab_contents/core_tab_helper.cc
+++ b/chrome/browser/ui/tab_contents/core_tab_helper.cc
@@ -7,6 +7,9 @@
 #include "base/command_line.h"
 #include "base/metrics/histogram.h"
 #include "chrome/browser/renderer_host/web_cache_manager.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_command_controller.h"
+#include "chrome/browser/ui/browser_finder.h"
 #include "chrome/common/chrome_switches.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
@@ -21,7 +24,8 @@
 
 CoreTabHelper::CoreTabHelper(WebContents* web_contents)
     : content::WebContentsObserver(web_contents),
-      delegate_(NULL) {
+      delegate_(NULL),
+      content_restrictions_(0) {
 }
 
 CoreTabHelper::~CoreTabHelper() {
@@ -38,6 +42,9 @@
   }
 
   switch (web_contents()->GetLoadState().state) {
+    case net::LOAD_STATE_WAITING_FOR_STALLED_SOCKET_POOL:
+    case net::LOAD_STATE_WAITING_FOR_AVAILABLE_SOCKET:
+      return l10n_util::GetStringUTF16(IDS_LOAD_STATE_WAITING_FOR_SOCKET_SLOT);
     case net::LOAD_STATE_WAITING_FOR_DELEGATE:
       if (!web_contents()->GetLoadState().param.empty()) {
         return l10n_util::GetStringFUTF16(IDS_LOAD_STATE_WAITING_FOR_DELEGATE,
@@ -107,9 +114,24 @@
     unload_detached_start_time_ = base::TimeTicks::Now();
 }
 
+void CoreTabHelper::UpdateContentRestrictions(int content_restrictions) {
+  content_restrictions_ = content_restrictions;
+#if !defined(OS_ANDROID)
+  Browser* browser = chrome::FindBrowserWithWebContents(web_contents());
+  if (!browser)
+    return;
+
+  browser->command_controller()->ContentRestrictionsChanged();
+#endif
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // WebContentsObserver overrides
 
+void CoreTabHelper::DidStartLoading(content::RenderViewHost* render_view_host) {
+  UpdateContentRestrictions(0);
+}
+
 void CoreTabHelper::WasShown() {
   WebCacheManager::GetInstance()->ObserveActivity(
       web_contents()->GetRenderProcessHost()->GetID());
diff --git a/chrome/browser/ui/tab_contents/core_tab_helper.h b/chrome/browser/ui/tab_contents/core_tab_helper.h
index c8e6782..7f0ffe3 100644
--- a/chrome/browser/ui/tab_contents/core_tab_helper.h
+++ b/chrome/browser/ui/tab_contents/core_tab_helper.h
@@ -39,6 +39,8 @@
   // Set the time during close when the tab is no longer visible.
   void OnUnloadDetachedStarted();
 
+  void UpdateContentRestrictions(int content_restrictions);
+
   CoreTabHelperDelegate* delegate() const { return delegate_; }
   void set_delegate(CoreTabHelperDelegate* d) { delegate_ = d; }
 
@@ -47,12 +49,15 @@
   }
 
   base::TimeTicks new_tab_start_time() const { return new_tab_start_time_; }
+  int content_restrictions() const { return content_restrictions_; }
 
  private:
   explicit CoreTabHelper(content::WebContents* web_contents);
   friend class content::WebContentsUserData<CoreTabHelper>;
 
   // content::WebContentsObserver overrides:
+  virtual void DidStartLoading(
+      content::RenderViewHost* render_view_host) OVERRIDE;
   virtual void WasShown() OVERRIDE;
   virtual void WebContentsDestroyed(
       content::WebContents* web_contents) OVERRIDE;
@@ -75,6 +80,10 @@
   // The time when the tab was removed from view during close.
   base::TimeTicks unload_detached_start_time_;
 
+  // Content restrictions, used to disable print/copy etc based on content's
+  // (full-page plugins for now only) permissions.
+  int content_restrictions_;
+
   DISALLOW_COPY_AND_ASSIGN(CoreTabHelper);
 };
 
diff --git a/chrome/browser/ui/tab_modal_confirm_dialog.h b/chrome/browser/ui/tab_modal_confirm_dialog.h
index 6bd54ac..838e705 100644
--- a/chrome/browser/ui/tab_modal_confirm_dialog.h
+++ b/chrome/browser/ui/tab_modal_confirm_dialog.h
@@ -12,7 +12,7 @@
 }
 
 // Base class for the tab modal confirm dialog.
-class TabModalConfirmDialog : public TabModalConfirmDialogCloseDelegate {
+class TabModalConfirmDialog : public TabModalConfirmDialogOperationsDelegate {
  public:
   // Platform specific factory function. This function will automatically show
   // the dialog.
@@ -24,9 +24,11 @@
   // Cancels the dialog.
   virtual void CancelTabModalDialog() = 0;
 
-  // TabModalConfirmDialogCloseDelegate:
+  // TabModalConfirmDialogOperationsDelegate:
   // Closes the dialog.
   virtual void CloseDialog() = 0;
+  // Prevents the dialog from closing on WebContents load start.
+  virtual void SetPreventCloseOnLoadStart(bool prevent) = 0;
 
  protected:
   virtual ~TabModalConfirmDialog() {}
diff --git a/chrome/browser/ui/tab_modal_confirm_dialog_browsertest.cc b/chrome/browser/ui/tab_modal_confirm_dialog_browsertest.cc
index 1ced79b..b4355ba 100644
--- a/chrome/browser/ui/tab_modal_confirm_dialog_browsertest.cc
+++ b/chrome/browser/ui/tab_modal_confirm_dialog_browsertest.cc
@@ -14,10 +14,8 @@
 #include "testing/gtest/include/gtest/gtest.h"
 
 MockTabModalConfirmDialogDelegate::MockTabModalConfirmDialogDelegate(
-    content::WebContents* web_contents,
     Delegate* delegate)
-    : TabModalConfirmDialogDelegate(web_contents),
-      delegate_(delegate) {
+    : delegate_(delegate) {
 }
 
 MockTabModalConfirmDialogDelegate::~MockTabModalConfirmDialogDelegate() {
@@ -49,8 +47,7 @@
 }
 
 void TabModalConfirmDialogTest::SetUpOnMainThread() {
-  delegate_ = new MockTabModalConfirmDialogDelegate(
-      browser()->tab_strip_model()->GetActiveWebContents(), this);
+  delegate_ = new MockTabModalConfirmDialogDelegate(this);
   dialog_ = TabModalConfirmDialog::Create(
       delegate_, browser()->tab_strip_model()->GetActiveWebContents());
   content::RunAllPendingInMessageLoop();
diff --git a/chrome/browser/ui/tab_modal_confirm_dialog_browsertest.h b/chrome/browser/ui/tab_modal_confirm_dialog_browsertest.h
index 0f22b37..0c0fd15 100644
--- a/chrome/browser/ui/tab_modal_confirm_dialog_browsertest.h
+++ b/chrome/browser/ui/tab_modal_confirm_dialog_browsertest.h
@@ -21,8 +21,7 @@
     virtual ~Delegate() {}
   };
 
-  MockTabModalConfirmDialogDelegate(content::WebContents* web_contents,
-                                    Delegate* delegate);
+  MockTabModalConfirmDialogDelegate(Delegate* delegate);
   virtual ~MockTabModalConfirmDialogDelegate();
 
   virtual string16 GetTitle() OVERRIDE;
diff --git a/chrome/browser/ui/tab_modal_confirm_dialog_delegate.cc b/chrome/browser/ui/tab_modal_confirm_dialog_delegate.cc
index c8d87ea..d2711dc 100644
--- a/chrome/browser/ui/tab_modal_confirm_dialog_delegate.cc
+++ b/chrome/browser/ui/tab_modal_confirm_dialog_delegate.cc
@@ -4,31 +4,20 @@
 
 #include "chrome/browser/ui/tab_modal_confirm_dialog_delegate.h"
 
-#include "chrome/browser/chrome_notification_types.h"
-#include "content/public/browser/navigation_controller.h"
-#include "content/public/browser/notification_source.h"
-#include "content/public/browser/web_contents.h"
 #include "grit/generated_resources.h"
 #include "ui/base/l10n/l10n_util.h"
 
-using content::NavigationController;
 using content::WebContents;
 
-TabModalConfirmDialogDelegate::TabModalConfirmDialogDelegate(
-    WebContents* web_contents)
-    : close_delegate_(NULL),
+TabModalConfirmDialogDelegate::TabModalConfirmDialogDelegate()
+    : operations_delegate_(NULL),
       closing_(false) {
-  NavigationController* controller = &web_contents->GetController();
-  registrar_.Add(this, content::NOTIFICATION_LOAD_START,
-                 content::Source<NavigationController>(controller));
-  registrar_.Add(this, chrome::NOTIFICATION_TAB_CLOSING,
-                 content::Source<NavigationController>(controller));
 }
 
 TabModalConfirmDialogDelegate::~TabModalConfirmDialogDelegate() {
   // If we end up here, the window has been closed, so make sure we don't close
   // it again.
-  close_delegate_ = NULL;
+  operations_delegate_ = NULL;
   // Make sure everything is cleaned up.
   Cancel();
 }
@@ -63,20 +52,6 @@
   CloseDialog();
 }
 
-void TabModalConfirmDialogDelegate::Observe(
-    int type,
-    const content::NotificationSource& source,
-    const content::NotificationDetails& details) {
-  // Close the dialog if we load a page (because the action might not apply to
-  // the same page anymore) or if the tab is closed.
-  if (type == content::NOTIFICATION_LOAD_START ||
-      type == chrome::NOTIFICATION_TAB_CLOSING) {
-    Cancel();
-  } else {
-    NOTREACHED();
-  }
-}
-
 gfx::Image* TabModalConfirmDialogDelegate::GetIcon() {
   return NULL;
 }
@@ -112,6 +87,6 @@
 }
 
 void TabModalConfirmDialogDelegate::CloseDialog() {
-  if (close_delegate_)
-    close_delegate_->CloseDialog();
+  if (operations_delegate_)
+    operations_delegate_->CloseDialog();
 }
diff --git a/chrome/browser/ui/tab_modal_confirm_dialog_delegate.h b/chrome/browser/ui/tab_modal_confirm_dialog_delegate.h
index e58e00d..29413a1 100644
--- a/chrome/browser/ui/tab_modal_confirm_dialog_delegate.h
+++ b/chrome/browser/ui/tab_modal_confirm_dialog_delegate.h
@@ -8,8 +8,6 @@
 #include "base/callback.h"
 #include "base/compiler_specific.h"
 #include "base/strings/string16.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
 #include "ui/base/window_open_disposition.h"
 
 namespace content {
@@ -20,26 +18,30 @@
 class Image;
 }
 
-class TabModalConfirmDialogCloseDelegate {
+// Operations to be performed on the dialog by the
+// TabModalConfirmDialogDelegate.
+class TabModalConfirmDialogOperationsDelegate {
  public:
-  TabModalConfirmDialogCloseDelegate() {}
-  virtual ~TabModalConfirmDialogCloseDelegate() {}
+  TabModalConfirmDialogOperationsDelegate() {}
+  virtual ~TabModalConfirmDialogOperationsDelegate() {}
 
   virtual void CloseDialog() = 0;
+  virtual void SetPreventCloseOnLoadStart(bool prevent) = 0;
 
  private:
-  DISALLOW_COPY_AND_ASSIGN(TabModalConfirmDialogCloseDelegate);
+  DISALLOW_COPY_AND_ASSIGN(TabModalConfirmDialogOperationsDelegate);
 };
 
 // This class acts as the delegate for a simple tab-modal dialog confirming
 // whether the user wants to execute a certain action.
-class TabModalConfirmDialogDelegate : public content::NotificationObserver {
+class TabModalConfirmDialogDelegate {
  public:
-  explicit TabModalConfirmDialogDelegate(content::WebContents* web_contents);
+  TabModalConfirmDialogDelegate();
   virtual ~TabModalConfirmDialogDelegate();
 
-  void set_close_delegate(TabModalConfirmDialogCloseDelegate* close_delegate) {
-    close_delegate_ = close_delegate;
+  void set_operations_delegate(
+      TabModalConfirmDialogOperationsDelegate* operations_delegate) {
+    operations_delegate_ = operations_delegate;
   }
 
   // Accepts the confirmation prompt and calls |OnAccepted|.
@@ -81,18 +83,10 @@
   virtual const char* GetCancelButtonIcon();
 
  protected:
-  TabModalConfirmDialogCloseDelegate* close_delegate() {
-    return close_delegate_;
+  TabModalConfirmDialogOperationsDelegate* operations_delegate() {
+    return operations_delegate_;
   }
 
-  // content::NotificationObserver implementation.
-  // Watch for a new load or a closed tab and dismiss the dialog if they occur.
-  virtual void Observe(int type,
-                       const content::NotificationSource& source,
-                       const content::NotificationDetails& details) OVERRIDE;
-
-  content::NotificationRegistrar registrar_;
-
  private:
   // It is guaranteed that exactly one of |OnAccepted|, |OnCanceled| or
   // |OnLinkClicked| is eventually called. These method are private to
@@ -109,7 +103,7 @@
   // Close the dialog.
   void CloseDialog();
 
-  TabModalConfirmDialogCloseDelegate* close_delegate_;
+  TabModalConfirmDialogOperationsDelegate* operations_delegate_;
   // True iff we are in the process of closing, to avoid running callbacks
   // multiple times.
   bool closing_;
diff --git a/chrome/browser/ui/toolbar/action_box_button_controller.cc b/chrome/browser/ui/toolbar/action_box_button_controller.cc
deleted file mode 100644
index 253756c..0000000
--- a/chrome/browser/ui/toolbar/action_box_button_controller.cc
+++ /dev/null
@@ -1,184 +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/toolbar/action_box_button_controller.h"
-
-#include "base/logging.h"
-#include "base/metrics/histogram.h"
-#include "base/strings/utf_string_conversions.h"
-#include "chrome/app/chrome_command_ids.h"
-#include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/extensions/api/page_launcher/page_launcher_api.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/bookmarks/bookmark_tab_helper.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_commands.h"
-#include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "chrome/browser/ui/toolbar/action_box_menu_model.h"
-#include "chrome/common/extensions/api/extension_action/action_info.h"
-#include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/extension_set.h"
-#include "content/public/browser/notification_service.h"
-#include "content/public/browser/notification_source.h"
-#include "content/public/browser/render_widget_host_view.h"
-#include "content/public/browser/user_metrics.h"
-#include "content/public/browser/web_contents.h"
-#include "grit/generated_resources.h"
-#include "grit/theme_resources.h"
-#include "ui/base/resource/resource_bundle.h"
-
-
-using content::UserMetricsAction;
-using content::WebContents;
-using extensions::ActionInfo;
-
-void ActionBoxButtonController::Delegate::ShowMenu(
-    scoped_ptr<ActionBoxMenuModel> menu_model) {
-}
-
-ActionBoxButtonController::ActionBoxButtonController(Browser* browser,
-                                                     Delegate* delegate)
-    : browser_(browser),
-      delegate_(delegate),
-      next_command_id_(0) {
-  DCHECK(browser_);
-  DCHECK(delegate_);
-  registrar_.Add(this,
-                 chrome::NOTIFICATION_EXTENSION_UNLOADED,
-                 content::Source<Profile>(browser->profile()));
-}
-
-ActionBoxButtonController::~ActionBoxButtonController() {}
-
-scoped_ptr<ActionBoxMenuModel> ActionBoxButtonController::CreateMenuModel() {
-  // Build a menu model and display the menu.
-  scoped_ptr<ActionBoxMenuModel> menu_model(
-      new ActionBoxMenuModel(browser_->profile(), this));
-  ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
-
-  // In some unit tests, GetActiveWebContents can return NULL.
-  bool starred = browser_->tab_strip_model()->GetActiveWebContents() &&
-      BookmarkTabHelper::FromWebContents(browser_->tab_strip_model()->
-          GetActiveWebContents())->is_starred();
-  menu_model->AddItemWithStringId(
-      IDC_BOOKMARK_PAGE_FROM_STAR,
-      starred ? IDS_TOOLTIP_STARRED : IDS_TOOLTIP_STAR);
-  menu_model->SetIcon(
-      menu_model->GetIndexOfCommandId(IDC_BOOKMARK_PAGE_FROM_STAR),
-      rb.GetNativeImageNamed(starred ? IDR_STAR_LIT : IDR_STAR));
-
-  ExtensionService* extension_service =
-      extensions::ExtensionSystem::Get(browser_->profile())->
-          extension_service();
-  if (extension_service) {
-    const ExtensionSet* extensions = extension_service->extensions();
-    for (ExtensionSet::const_iterator it = extensions->begin();
-         it != extensions->end(); ++it) {
-      const extensions::Extension* extension = it->get();
-      if (ActionInfo::GetPageLauncherInfo(extension)) {
-        int command_id = GetCommandIdForExtension(*extension);
-        menu_model->AddExtension(*extension, command_id);
-      }
-    }
-  }
-  return menu_model.Pass();
-}
-
-void ActionBoxButtonController::OnButtonClicked() {
-  content::RecordAction(UserMetricsAction("ActionBox.ClickButton"));
-  delegate_->ShowMenu(CreateMenuModel());
-}
-
-bool ActionBoxButtonController::IsCommandIdChecked(int command_id) const {
-  return false;
-}
-
-bool ActionBoxButtonController::IsCommandIdEnabled(int command_id) const {
-  return true;
-}
-
-bool ActionBoxButtonController::GetAcceleratorForCommandId(
-    int command_id,
-    ui::Accelerator* accelerator) {
-  return false;
-}
-
-void ActionBoxButtonController::ExecuteCommand(int command_id,
-                                               int event_flags) {
-  // If the command id belongs to an extension, dispatch an onClicked event
-  // to its pageLauncher.
-  ExtensionIdCommandMap::const_iterator it =
-      extension_command_ids_.find(command_id);
-  if (it != extension_command_ids_.end()) {
-    WebContents* web_contents =
-        browser_->tab_strip_model()->GetActiveWebContents();
-
-    std::string page_title = UTF16ToUTF8(web_contents->GetTitle());
-    std::string selected_text =
-        UTF16ToUTF8(web_contents->GetRenderWidgetHostView()->GetSelectedText());
-    extensions::PageLauncherAPI::DispatchOnClickedEvent(
-        browser_->profile(),
-        it->second,
-        web_contents->GetURL(),
-        web_contents->GetContentsMimeType(),
-        page_title.empty() ? NULL : &page_title,
-        selected_text.empty() ? NULL : &selected_text);
-    return;
-  }
-
-  // Otherwise, let the browser handle the command.
-  chrome::ExecuteCommand(browser_, command_id);
-}
-
-int ActionBoxButtonController::GetCommandIdForExtension(
-    const extensions::Extension& extension) {
-  for (ExtensionIdCommandMap::const_iterator it =
-       extension_command_ids_.begin();
-       it != extension_command_ids_.end(); ++it) {
-    if (it->second == extension.id())
-      return it->first;
-  }
-
-  int command_id = GetNextCommandId();
-  extension_command_ids_[command_id] = extension.id();
-
-  return command_id;
-}
-
-int ActionBoxButtonController::GetNextCommandId() {
-  int command_id = next_command_id_;
-  // Find an available command id to return next time the function is called.
-  do {
-    next_command_id_++;
-    // Larger command ids are reserved for non-dynamic entries, so we start
-    // reusing old ids at this point.
-    if (next_command_id_ >= IDC_MinimumLabelValue)
-      next_command_id_ = 0;
-  } while (extension_command_ids_.find(next_command_id_) !=
-           extension_command_ids_.end());
-
-  return command_id;
-}
-
-void ActionBoxButtonController::Observe(
-    int type,
-    const content::NotificationSource& source,
-    const content::NotificationDetails& details) {
-  DCHECK_EQ(type, chrome::NOTIFICATION_EXTENSION_UNLOADED);
-  const extensions::Extension* extension =
-      content::Details<extensions::UnloadedExtensionInfo>(details)->extension;
-
-  // Remove any entry point command ids associated with the extension.
-  for (ExtensionIdCommandMap::iterator it = extension_command_ids_.begin();
-       it != extension_command_ids_.end();) {
-    if (it->second== extension->id())
-      extension_command_ids_.erase(it++);
-    else
-      ++it;
-  }
-  // TODO(kalman): if there's a menu open, remove it from that too.
-  // We may also want to listen to EXTENSION_LOADED to do the opposite.
-}
diff --git a/chrome/browser/ui/toolbar/action_box_button_controller.h b/chrome/browser/ui/toolbar/action_box_button_controller.h
deleted file mode 100644
index f61af21..0000000
--- a/chrome/browser/ui/toolbar/action_box_button_controller.h
+++ /dev/null
@@ -1,90 +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_TOOLBAR_ACTION_BOX_BUTTON_CONTROLLER_H_
-#define CHROME_BROWSER_UI_TOOLBAR_ACTION_BOX_BUTTON_CONTROLLER_H_
-
-#include <map>
-#include <string>
-
-#include "base/memory/scoped_ptr.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
-#include "ui/base/models/simple_menu_model.h"
-
-class ActionBoxMenuModel;
-class Browser;
-
-namespace extensions {
-class Extension;
-}
-
-namespace ui {
-class MenuModel;
-}
-
-// Controller for the action box.
-//
-// This should have the same lifetime as the action box itself -- that is, more
-// or less the lifetime of the tab -- unlike ActionBoxMenuModel which is scoped
-// to the menu being open.
-class ActionBoxButtonController : public ui::SimpleMenuModel::Delegate,
-                                  public content::NotificationObserver {
- public:
-  class Delegate {
-   public:
-    // Shows the menu with the given |menu_model|.
-    virtual void ShowMenu(scoped_ptr<ActionBoxMenuModel> menu_model);
-
-   protected:
-    virtual ~Delegate() {}
-  };
-
-  ActionBoxButtonController(Browser* browser, Delegate* delegate);
-  virtual ~ActionBoxButtonController();
-
-  // Creates and populates an ActionBoxMenuModel according to the current
-  // state of the browser.
-  scoped_ptr<ActionBoxMenuModel> CreateMenuModel();
-
-  // Notifies this that the action box button has been clicked.
-  // Methods on the Delegate may be called re-entrantly.
-  void OnButtonClicked();
-
-  // Overridden from ui::SimpleMenuModel::Delegate:
-  virtual bool IsCommandIdChecked(int command_id) const OVERRIDE;
-  virtual bool IsCommandIdEnabled(int command_id) const OVERRIDE;
-  virtual bool GetAcceleratorForCommandId(
-      int command_id,
-      ui::Accelerator* accelerator) OVERRIDE;
-  virtual void ExecuteCommand(int command_id, int event_flags) OVERRIDE;
-
- private:
-  // Gets the command ID for an extension, creating a new one if necessary.
-  int GetCommandIdForExtension(const extensions::Extension& extension);
-
-  // Returns the next command ID to be used.
-  int GetNextCommandId();
-
-  // content::NotificationObserver implementation.
-  virtual void Observe(int type,
-                       const content::NotificationSource& source,
-                       const content::NotificationDetails& details) OVERRIDE;
-
-  Browser* browser_;
-
-  Delegate* delegate_;
-
-  typedef std::map<int, std::string> ExtensionIdCommandMap;
-  ExtensionIdCommandMap extension_command_ids_;
-
-  // The command ID to assign to the next dynamic entry that needs one.
-  int next_command_id_;
-
-  content::NotificationRegistrar registrar_;
-
-  DISALLOW_COPY_AND_ASSIGN(ActionBoxButtonController);
-};
-
-#endif  // CHROME_BROWSER_UI_TOOLBAR_ACTION_BOX_BUTTON_CONTROLLER_H_
diff --git a/chrome/browser/ui/toolbar/action_box_context_menu_controller.cc b/chrome/browser/ui/toolbar/action_box_context_menu_controller.cc
deleted file mode 100644
index 4978c3a..0000000
--- a/chrome/browser/ui/toolbar/action_box_context_menu_controller.cc
+++ /dev/null
@@ -1,173 +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/toolbar/action_box_context_menu_controller.h"
-
-#include "base/logging.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/strings/string_util.h"
-#include "base/strings/utf_string_conversions.h"
-#include "chrome/app/chrome_command_ids.h"
-#include "chrome/browser/extensions/extension_service.h"
-#include "chrome/browser/extensions/extension_system.h"
-#include "chrome/browser/extensions/extension_uninstall_dialog.h"
-#include "chrome/browser/extensions/management_policy.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/chrome_pages.h"
-#include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/manifest_url_handler.h"
-#include "content/public/browser/page_navigator.h"
-#include "content/public/common/page_transition_types.h"
-#include "content/public/common/referrer.h"
-#include "grit/chromium_strings.h"
-#include "grit/generated_resources.h"
-#include "ui/base/models/menu_separator_types.h"
-#include "ui/base/window_open_disposition.h"
-#include "url/gurl.h"
-
-using extensions::Extension;
-
-namespace {
-
-// Takes care of running the uninstall extension dialog. This class deletes
-// itself after the user has responded to the dialog.
-class ExtensionUninstaller : public ExtensionUninstallDialog::Delegate {
- public:
-  ExtensionUninstaller(Browser* browser, Profile* profile);
-
-  void ShowDialog(const Extension* extension);
-
-  // ExtensionUninstallDialog::Delegate:
-  virtual void ExtensionUninstallAccepted() OVERRIDE;
-  virtual void ExtensionUninstallCanceled() OVERRIDE;
-
- private:
-  virtual ~ExtensionUninstaller();
-
-  scoped_ptr<ExtensionUninstallDialog> dialog_;
-  std::string extension_id_;
-  Profile* profile_;
-
-  DISALLOW_COPY_AND_ASSIGN(ExtensionUninstaller);
-};
-
-ExtensionUninstaller::ExtensionUninstaller(Browser* browser, Profile* profile)
-    : dialog_(ExtensionUninstallDialog::Create(profile,
-                                               browser,
-                                               this)),
-      profile_(profile) {
-}
-
-ExtensionUninstaller::~ExtensionUninstaller() {
-}
-
-void ExtensionUninstaller::ShowDialog(const Extension* extension) {
-  extension_id_ = extension->id();
-  dialog_->ConfirmUninstall(extension);
-}
-
-void ExtensionUninstaller::ExtensionUninstallAccepted() {
-  ExtensionService* extension_service =
-      extensions::ExtensionSystem::Get(profile_)->extension_service();
-  if (extension_service->GetInstalledExtension(extension_id_))
-    extension_service->UninstallExtension(extension_id_, false, NULL);
-  delete this;
-}
-
-void ExtensionUninstaller::ExtensionUninstallCanceled() {
-  delete this;
-}
-
-}  // namespace
-
-ActionBoxContextMenuController::ActionBoxContextMenuController(
-    Browser* browser,
-    const Extension* extension)
-    : browser_(browser),
-      extension_id_(extension->id()),
-      menu_model_(this) {
-  std::string extension_name = extension->name();
-  // Ampersands need to be escaped to avoid being treated like
-  // mnemonics in the menu.
-  ReplaceChars(extension_name, "&", "&&", &extension_name);
-  menu_model_.AddItem(IDC_ACTION_BOX_EXTENSION_HOMEPAGE,
-                      UTF8ToUTF16(extension_name));
-  menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
-  menu_model_.AddItemWithStringId(IDC_ACTION_BOX_EXTENSION_MANAGE,
-                                  IDS_MANAGE_EXTENSION);
-  menu_model_.AddItemWithStringId(IDC_ACTION_BOX_EXTENSION_UNINSTALL,
-                                  IDS_EXTENSIONS_UNINSTALL);
-}
-
-ActionBoxContextMenuController::~ActionBoxContextMenuController() {
-}
-
-bool ActionBoxContextMenuController::IsCommandIdChecked(int command_id) const {
-  return false;
-}
-
-bool ActionBoxContextMenuController::IsCommandIdEnabled(int command_id) const {
-  const Extension* extension = GetExtension();
-  if (!extension)
-    return false;
-
-  switch (command_id) {
-    case IDC_ACTION_BOX_EXTENSION_HOMEPAGE:
-      return extensions::ManifestURL::GetHomepageURL(extension).is_valid();
-    case IDC_ACTION_BOX_EXTENSION_MANAGE:
-      return true;
-    case IDC_ACTION_BOX_EXTENSION_UNINSTALL: {
-      return extensions::ExtensionSystem::Get(browser_->profile())->
-          management_policy()->UserMayModifySettings(extension, NULL);
-    }
-    default: {
-      NOTREACHED();
-      return false;
-    }
-  }
-}
-
-bool ActionBoxContextMenuController::GetAcceleratorForCommandId(
-    int command_id,
-    ui::Accelerator* accelerator) {
-  return false;
-}
-
-void ActionBoxContextMenuController::ExecuteCommand(int command_id,
-                                                    int event_flags) {
-  const Extension* extension = GetExtension();
-  if (!extension)
-    return;
-
-  switch (command_id) {
-    case IDC_ACTION_BOX_EXTENSION_HOMEPAGE: {
-      content::OpenURLParams params(
-          extensions::ManifestURL::GetHomepageURL(extension),
-          content::Referrer(), NEW_FOREGROUND_TAB,
-          content::PAGE_TRANSITION_LINK, false);
-      browser_->OpenURL(params);
-      break;
-    }
-    case IDC_ACTION_BOX_EXTENSION_MANAGE: {
-      chrome::ShowExtensions(browser_, extension->id());
-      break;
-    }
-    case IDC_ACTION_BOX_EXTENSION_UNINSTALL: {
-      ExtensionUninstaller* uninstaller =
-          new ExtensionUninstaller(browser_, browser_->profile());
-      uninstaller->ShowDialog(extension);
-      break;
-    }
-    default:
-      NOTREACHED();
-  }
-}
-
-const Extension* ActionBoxContextMenuController::GetExtension() const {
-  ExtensionService* extension_service =
-      extensions::ExtensionSystem::Get(browser_->profile())->
-          extension_service();
-  return extension_service->GetInstalledExtension(extension_id_);
-}
diff --git a/chrome/browser/ui/toolbar/action_box_context_menu_controller.h b/chrome/browser/ui/toolbar/action_box_context_menu_controller.h
deleted file mode 100644
index 92cf0e7..0000000
--- a/chrome/browser/ui/toolbar/action_box_context_menu_controller.h
+++ /dev/null
@@ -1,54 +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_TOOLBAR_ACTION_BOX_CONTEXT_MENU_CONTROLLER_H__
-#define CHROME_BROWSER_UI_TOOLBAR_ACTION_BOX_CONTEXT_MENU_CONTROLLER_H__
-
-#include <string>
-
-#include "base/basictypes.h"
-#include "ui/base/models/simple_menu_model.h"
-
-class Browser;
-
-namespace extensions {
-class Extension;
-}  // namespace extensions
-
-namespace ui {
-class Accelerator;
-class MenuModel;
-}  // namespace ui
-
-// This class handles building a context menu for extensions in the action
-// box. It also contains the logic necessary for executing the actions
-// associated with each menu entry.
-class ActionBoxContextMenuController : public ui::SimpleMenuModel::Delegate {
- public:
-  // |browser| and |extension| must not be NULL.
-  ActionBoxContextMenuController(Browser* browser,
-                                 const extensions::Extension* extension);
-  virtual ~ActionBoxContextMenuController();
-
-  ui::MenuModel* menu_model() { return &menu_model_; }
-
-  // ui::SimpleMenuModel::Delegate:
-  virtual bool IsCommandIdChecked(int command_id) const OVERRIDE;
-  virtual bool IsCommandIdEnabled(int command_id) const OVERRIDE;
-  virtual bool GetAcceleratorForCommandId(
-      int command_id,
-      ui::Accelerator* accelerator) OVERRIDE;
-  virtual void ExecuteCommand(int command_id, int event_flags) OVERRIDE;
-
- private:
-  const extensions::Extension* GetExtension() const;
-
-  Browser* browser_;
-  std::string extension_id_;
-  ui::SimpleMenuModel menu_model_;
-
-  DISALLOW_COPY_AND_ASSIGN(ActionBoxContextMenuController);
-};
-
-#endif  // CHROME_BROWSER_UI_TOOLBAR_ACTION_BOX_CONTEXT_MENU_CONTROLLER_H__
diff --git a/chrome/browser/ui/toolbar/action_box_menu_model.cc b/chrome/browser/ui/toolbar/action_box_menu_model.cc
deleted file mode 100644
index 9a5197a..0000000
--- a/chrome/browser/ui/toolbar/action_box_menu_model.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/ui/toolbar/action_box_menu_model.h"
-
-#include "base/logging.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/extension_toolbar_model.h"
-#include "chrome/common/extensions/api/extension_action/action_info.h"
-
-
-using extensions::ActionInfo;
-
-////////////////////////////////////////////////////////////////////////////////
-// ActionBoxMenuModel
-
-ActionBoxMenuModel::ActionBoxMenuModel(Profile* profile,
-                                       ui::SimpleMenuModel::Delegate* delegate)
-    : ui::SimpleMenuModel(delegate),
-      profile_(profile) {
-
-}
-
-ActionBoxMenuModel::~ActionBoxMenuModel() {
-}
-
-void ActionBoxMenuModel::AddExtension(const extensions::Extension& extension,
-                                      int command_id) {
-  if (extension_ids_.empty())
-    AddSeparator(ui::NORMAL_SEPARATOR);
-  extension_ids_.push_back(extension.id());
-  const ActionInfo* page_launcher_info =
-      ActionInfo::GetPageLauncherInfo(&extension);
-  DCHECK(page_launcher_info);
-  AddItem(command_id, UTF8ToUTF16(page_launcher_info->default_title));
-}
-
-bool ActionBoxMenuModel::IsItemExtension(int index) {
-  // The extensions are always at the end of the model.
-  CHECK(index < GetItemCount());
-  return index >= GetFirstExtensionIndex();
-}
-
-const extensions::Extension* ActionBoxMenuModel::GetExtensionAt(int index) {
-  if (!IsItemExtension(index))
-    return NULL;
-
-  int index_in_extension_ids = index - GetFirstExtensionIndex();
-  CHECK_GE(index_in_extension_ids, 0);
-  CHECK_LT(index_in_extension_ids, static_cast<int>(extension_ids_.size()));
-
-  ExtensionService* extension_service =
-      extensions::ExtensionSystem::Get(profile_)->extension_service();
-  return extension_service->extensions()->GetByID(
-      extension_ids_[index_in_extension_ids]);
-}
-
-void ActionBoxMenuModel::ExecuteCommand(int command_id) {
-  delegate()->ExecuteCommand(command_id, 0);
-}
-
-int ActionBoxMenuModel::GetFirstExtensionIndex() {
-  return GetItemCount() - extension_ids_.size();
-}
diff --git a/chrome/browser/ui/toolbar/action_box_menu_model.h b/chrome/browser/ui/toolbar/action_box_menu_model.h
deleted file mode 100644
index 02c21a8..0000000
--- a/chrome/browser/ui/toolbar/action_box_menu_model.h
+++ /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.
-
-#ifndef CHROME_BROWSER_UI_TOOLBAR_ACTION_BOX_MENU_MODEL_H_
-#define CHROME_BROWSER_UI_TOOLBAR_ACTION_BOX_MENU_MODEL_H_
-
-#include <map>
-
-#include "chrome/common/extensions/extension.h"
-#include "content/public/browser/notification_observer.h"
-#include "ui/base/models/simple_menu_model.h"
-
-class Profile;
-
-// A menu model that builds the contents of the action box menu. Effectively,
-// a ui::SimpleMenuModel with methods specifically for dealing with extension
-// content.
-//
-// This model should be built on demand since its content reflects the state of
-// the browser at creation time.
-class ActionBoxMenuModel : public ui::SimpleMenuModel {
- public:
-  ActionBoxMenuModel(Profile* profile, ui::SimpleMenuModel::Delegate* delegate);
-  virtual ~ActionBoxMenuModel();
-
-  // Adds an extension to the model with a given command ID.
-  void AddExtension(const extensions::Extension& extension, int command_id);
-
-  // Returns true if item associated with an extension.
-  bool IsItemExtension(int index);
-
-  // Returns an extension associated with model item at |index|
-  // or NULL if it is not an extension item.
-  const extensions::Extension* GetExtensionAt(int index);
-
-  // Calls ExecuteCommand on the delegate.
-  void ExecuteCommand(int command_id);
-
- private:
-  friend class ActionBoxMenuModelTest;
-  // Gets the index of the first extension. This may be equal to the number of
-  // total items in the model if there are no extensions installed.
-  int GetFirstExtensionIndex();
-
-  Profile* profile_;
-
-  // The list of extensions added to the menu, in order, if any.
-  extensions::ExtensionIdList extension_ids_;
-
-  DISALLOW_COPY_AND_ASSIGN(ActionBoxMenuModel);
-};
-
-#endif  // CHROME_BROWSER_UI_TOOLBAR_ACTION_BOX_MENU_MODEL_H_
diff --git a/chrome/browser/ui/toolbar/action_box_menu_model_unittest.cc b/chrome/browser/ui/toolbar/action_box_menu_model_unittest.cc
deleted file mode 100644
index 8b5b419..0000000
--- a/chrome/browser/ui/toolbar/action_box_menu_model_unittest.cc
+++ /dev/null
@@ -1,129 +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/toolbar/action_box_menu_model.h"
-
-#include "base/memory/scoped_ptr.h"
-#include "base/prefs/testing_pref_service.h"
-#include "base/values.h"
-#include "chrome/app/chrome_command_ids.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_command_controller.h"
-#include "chrome/browser/ui/browser_commands.h"
-#include "chrome/browser/ui/toolbar/action_box_button_controller.h"
-#include "chrome/common/extensions/feature_switch.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 "chrome/test/base/ui_test_utils.h"
-#include "grit/generated_resources.h"
-#include "grit/theme_resources.h"
-#include "sync/notifier/invalidation_util.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "ui/base/resource/resource_bundle.h"
-
-using extensions::FeatureSwitch;
-
-class ActionBoxMenuModelTest : public BrowserWithTestWindowTest,
-                               public ActionBoxButtonController::Delegate {
- public:
-  ActionBoxMenuModelTest() {}
-
-  virtual void SetUp() OVERRIDE {
-    BrowserWithTestWindowTest::SetUp();
-    controller_.reset(new ActionBoxButtonController(browser(), this));
-  }
-
-  virtual void TearDown() OVERRIDE {
-    controller_.reset();
-    BrowserWithTestWindowTest::TearDown();
-  }
-
-  scoped_ptr<ActionBoxMenuModel> CreateModel() {
-    return controller_->CreateMenuModel();
-  }
-
-  void InitProfile(){
-    profile()->set_incognito(true);
-    profile()->GetPrefs()->ClearPref(prefs::kGoogleServicesUsername);
-  }
-
-  void SetProfileSignedIn() {
-    profile()->set_incognito(false);
-    // Set username pref (i.e. sign in),
-    profile()->GetPrefs()->SetString(prefs::kGoogleServicesUsername, "foo");
-  }
-
-  void NavigateToBookmarkablePage() {
-    AddTab(browser(), GURL("http://www.google.com"));
-  }
-
-  void NavigateToLocalPage() {
-    AddTab(browser(), GURL("chrome://blank"));
-  }
-
- private:
-  scoped_ptr<ActionBoxButtonController> controller_;
-
-  DISALLOW_COPY_AND_ASSIGN(ActionBoxMenuModelTest);
-};
-
-// Tests that Bookmark Star is lit up only on bookmarked pages.
-TEST_F(ActionBoxMenuModelTest, BookmarkedPage) {
-  FeatureSwitch::ScopedOverride enable_action_box(FeatureSwitch::action_box(),
-                                                  true);
-  // Set up bookmark model
-  profile()->CreateBookmarkModel(true);
-  ui_test_utils::WaitForBookmarkModelToLoad(profile());
-
-  // Navigate to a url.
-  GURL url1("http://www.google.com");
-  AddTab(browser(), url1);
-
-  scoped_ptr<ActionBoxMenuModel> model = CreateModel();
-
-  // Bokomark item should be in menu.
-  int bookmark_item_index = model->GetIndexOfCommandId(
-      IDC_BOOKMARK_PAGE_FROM_STAR);
-  ASSERT_NE(-1, bookmark_item_index);
-
-  gfx::Image bookmark_icon;
-  gfx::Image unlit_icon;
-  gfx::Image lit_icon;
-
-  model->GetIconAt(bookmark_item_index, &bookmark_icon);
-  unlit_icon =
-      ui::ResourceBundle::GetSharedInstance().GetNativeImageNamed(IDR_STAR);
-
-  SkBitmap bookmark_icon_bitmap = *bookmark_icon.ToSkBitmap();
-  SkBitmap unlit_icon_bitmap = *unlit_icon.ToSkBitmap();
-  SkAutoLockPixels a(bookmark_icon_bitmap);
-  SkAutoLockPixels b(unlit_icon_bitmap);
-
-  // Verify that the icon in the menu is the unlit icon.
-  EXPECT_EQ(0, memcmp(bookmark_icon_bitmap.getPixels(),
-                      unlit_icon_bitmap.getPixels(),
-                      unlit_icon_bitmap.getSize()));
-
-  // Now bookmark it.
-  chrome::BookmarkCurrentPage(browser());
-
-  scoped_ptr<ActionBoxMenuModel> model2 = CreateModel();
-
-  model2->GetIconAt(bookmark_item_index, &bookmark_icon);
-  lit_icon =
-      ui::ResourceBundle::GetSharedInstance().GetNativeImageNamed(IDR_STAR_LIT);
-
-  SkBitmap bookmark_icon_bitmap2 = *bookmark_icon.ToSkBitmap();
-  SkBitmap lit_icon_bitmap = *lit_icon.ToSkBitmap();
-  SkAutoLockPixels c(bookmark_icon_bitmap2);
-  SkAutoLockPixels d(lit_icon_bitmap);
-
-
-  // Verify that the icon in the menu is the lit icon.
-  EXPECT_EQ(0, memcmp(bookmark_icon_bitmap2.getPixels(),
-                      lit_icon_bitmap.getPixels(),
-                      lit_icon_bitmap.getSize()));
-}
diff --git a/chrome/browser/ui/toolbar/test_toolbar_model.cc b/chrome/browser/ui/toolbar/test_toolbar_model.cc
index 3b452a7..95411b3 100644
--- a/chrome/browser/ui/toolbar/test_toolbar_model.cc
+++ b/chrome/browser/ui/toolbar/test_toolbar_model.cc
@@ -29,11 +29,13 @@
   return url_;
 }
 
-bool TestToolbarModel::WouldReplaceSearchURLWithSearchTerms() const {
+bool TestToolbarModel::WouldReplaceSearchURLWithSearchTerms(
+    bool ignore_editing) const {
   return should_replace_url_;
 }
 
-ToolbarModel::SecurityLevel TestToolbarModel::GetSecurityLevel() const {
+ToolbarModel::SecurityLevel TestToolbarModel::GetSecurityLevel(
+    bool ignore_editing) const {
   return security_level_;
 }
 
diff --git a/chrome/browser/ui/toolbar/test_toolbar_model.h b/chrome/browser/ui/toolbar/test_toolbar_model.h
index 256cb2c..80b9f19 100644
--- a/chrome/browser/ui/toolbar/test_toolbar_model.h
+++ b/chrome/browser/ui/toolbar/test_toolbar_model.h
@@ -20,8 +20,9 @@
       bool display_search_urls_as_search_terms) const OVERRIDE;
   virtual string16 GetCorpusNameForMobile() const OVERRIDE;
   virtual GURL GetURL() const OVERRIDE;
-  virtual bool WouldReplaceSearchURLWithSearchTerms() const OVERRIDE;
-  virtual SecurityLevel GetSecurityLevel() const OVERRIDE;
+  virtual bool WouldReplaceSearchURLWithSearchTerms(
+      bool ignore_editing) const OVERRIDE;
+  virtual SecurityLevel GetSecurityLevel(bool ignore_editing) const OVERRIDE;
   virtual int GetIcon() const OVERRIDE;
   virtual string16 GetEVCertName() const OVERRIDE;
   virtual bool ShouldDisplayURL() const OVERRIDE;
diff --git a/chrome/browser/ui/toolbar/toolbar_model.h b/chrome/browser/ui/toolbar/toolbar_model.h
index 9ef715d..8238cb6 100644
--- a/chrome/browser/ui/toolbar/toolbar_model.h
+++ b/chrome/browser/ui/toolbar/toolbar_model.h
@@ -51,11 +51,17 @@
   virtual GURL GetURL() const = 0;
 
   // Returns true if a call to GetText(true) would successfully replace the URL
-  // with search terms.
-  virtual bool WouldReplaceSearchURLWithSearchTerms() const = 0;
+  // with search terms.  If |ignore_editing| is true, the result reflects the
+  // underlying state of the page without regard to any user edits that may be
+  // in progress in the omnibox.
+  virtual bool WouldReplaceSearchURLWithSearchTerms(bool ignore_editing)
+      const = 0;
 
-  // Returns the security level that the toolbar should display.
-  virtual SecurityLevel GetSecurityLevel() const = 0;
+  // Returns the security level that the toolbar should display.  If
+  // |ignore_editing| is true, the result reflects the underlying state of the
+  // page without regard to any user edits that may be in progress in the
+  // omnibox.
+  virtual SecurityLevel GetSecurityLevel(bool ignore_editing) const = 0;
 
   // Returns the resource_id of the icon to show to the left of the address,
   // based on the current URL.  This doesn't cover specialized icons while the
diff --git a/chrome/browser/ui/toolbar/toolbar_model_impl.cc b/chrome/browser/ui/toolbar/toolbar_model_impl.cc
index 8ecf05c..4e6f66b 100644
--- a/chrome/browser/ui/toolbar/toolbar_model_impl.cc
+++ b/chrome/browser/ui/toolbar/toolbar_model_impl.cc
@@ -93,7 +93,7 @@
 string16 ToolbarModelImpl::GetText(
     bool display_search_urls_as_search_terms) const {
   if (display_search_urls_as_search_terms) {
-    string16 search_terms(GetSearchTerms());
+    string16 search_terms(GetSearchTerms(false));
     if (!search_terms.empty())
       return search_terms;
   }
@@ -114,7 +114,7 @@
 }
 
 string16 ToolbarModelImpl::GetCorpusNameForMobile() const {
-  if (!WouldReplaceSearchURLWithSearchTerms())
+  if (!WouldReplaceSearchURLWithSearchTerms(false))
     return string16();
   GURL url(GetURL());
   // If there is a query in the url fragment look for the corpus name there,
@@ -145,8 +145,9 @@
   return GURL(content::kAboutBlankURL);
 }
 
-bool ToolbarModelImpl::WouldReplaceSearchURLWithSearchTerms() const {
-  return !GetSearchTerms().empty();
+bool ToolbarModelImpl::WouldReplaceSearchURLWithSearchTerms(
+    bool ignore_editing) const {
+  return !GetSearchTerms(ignore_editing).empty();
 }
 
 bool ToolbarModelImpl::ShouldDisplayURL() const {
@@ -181,15 +182,17 @@
   return true;
 }
 
-ToolbarModel::SecurityLevel ToolbarModelImpl::GetSecurityLevel() const {
-  if (input_in_progress_)  // When editing, assume no security style.
+ToolbarModel::SecurityLevel
+    ToolbarModelImpl::GetSecurityLevel(bool ignore_editing) const {
+  if (!ignore_editing && input_in_progress_) {
+    // When editing, assume no security style.
     return NONE;
-
+  }
   return GetSecurityLevelForWebContents(delegate_->GetActiveWebContents());
 }
 
 int ToolbarModelImpl::GetIcon() const {
-  if (WouldReplaceSearchURLWithSearchTerms())
+  if (WouldReplaceSearchURLWithSearchTerms(false))
     return IDR_OMNIBOX_SEARCH_SECURED;
 
   static int icon_ids[NUM_SECURITY_LEVELS] = {
@@ -201,11 +204,11 @@
     IDR_OMNIBOX_HTTPS_INVALID,
   };
   DCHECK(arraysize(icon_ids) == NUM_SECURITY_LEVELS);
-  return icon_ids[GetSecurityLevel()];
+  return icon_ids[GetSecurityLevel(false)];
 }
 
 string16 ToolbarModelImpl::GetEVCertName() const {
-  DCHECK_EQ(GetSecurityLevel(), EV_SECURE);
+  DCHECK_EQ(GetSecurityLevel(false), EV_SECURE);
   scoped_refptr<net::X509Certificate> cert;
   // Note: Navigation controller and active entry are guaranteed non-NULL or
   // the security level would be NONE.
@@ -252,7 +255,7 @@
       NULL;
 }
 
-string16 ToolbarModelImpl::GetSearchTerms() const {
+string16 ToolbarModelImpl::GetSearchTerms(bool ignore_editing) const {
   const WebContents* web_contents = delegate_->GetActiveWebContents();
   string16 search_terms(chrome::GetSearchTerms(web_contents));
   if (search_terms.empty())
@@ -270,15 +273,16 @@
       (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
+  // If the URL is using a Google base URL specified via the command line, we
+  // allow search term replacement any time the user isn't editing, bypassing
   // the security check below.
-  if (entry &&
+  if ((ignore_editing || !input_in_progress_) && 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();
+  ToolbarModel::SecurityLevel security_level = GetSecurityLevel(ignore_editing);
   return ((security_level == NONE) || (security_level == SECURITY_ERROR)) ?
       string16() : search_terms;
 }
diff --git a/chrome/browser/ui/toolbar/toolbar_model_impl.h b/chrome/browser/ui/toolbar/toolbar_model_impl.h
index 39b5707..651e809 100644
--- a/chrome/browser/ui/toolbar/toolbar_model_impl.h
+++ b/chrome/browser/ui/toolbar/toolbar_model_impl.h
@@ -41,8 +41,9 @@
       bool display_search_urls_as_search_terms) const OVERRIDE;
   virtual string16 GetCorpusNameForMobile() const OVERRIDE;
   virtual GURL GetURL() const OVERRIDE;
-  virtual bool WouldReplaceSearchURLWithSearchTerms() const OVERRIDE;
-  virtual SecurityLevel GetSecurityLevel() const OVERRIDE;
+  virtual bool WouldReplaceSearchURLWithSearchTerms(
+      bool ignore_editing) const OVERRIDE;
+  virtual SecurityLevel GetSecurityLevel(bool ignore_editing) const OVERRIDE;
   virtual int GetIcon() const OVERRIDE;
   virtual string16 GetEVCertName() const OVERRIDE;
   virtual bool ShouldDisplayURL() const OVERRIDE;
@@ -62,8 +63,10 @@
   Profile* GetProfile() const;
 
   // Returns search terms as in chrome::GetSearchTerms() unless the page is
-  // insufficiently secure.
-  string16 GetSearchTerms() const;
+  // insufficiently secure.  If |ignore_editing| is true, the result reflects
+  // the underlying state of the page without regard to any user edits that
+  // may be in progress in the omnibox.
+  string16 GetSearchTerms(bool ignore_editing) const;
 
   ToolbarModelDelegate* delegate_;
 
diff --git a/chrome/browser/ui/toolbar/toolbar_model_unittest.cc b/chrome/browser/ui/toolbar/toolbar_model_unittest.cc
index c3da77c..20595cb 100644
--- a/chrome/browser/ui/toolbar/toolbar_model_unittest.cc
+++ b/chrome/browser/ui/toolbar/toolbar_model_unittest.cc
@@ -235,7 +235,7 @@
   EXPECT_EQ(should_display, toolbar_model->ShouldDisplayURL());
   EXPECT_EQ(expected_text, toolbar_model->GetText(can_replace));
   EXPECT_EQ(would_replace,
-            toolbar_model->WouldReplaceSearchURLWithSearchTerms());
+            toolbar_model->WouldReplaceSearchURLWithSearchTerms(false));
 
   // Check after commit.
   CommitPendingLoad(controller);
@@ -248,7 +248,17 @@
   EXPECT_EQ(should_display, toolbar_model->ShouldDisplayURL());
   EXPECT_EQ(expected_text, toolbar_model->GetText(can_replace));
   EXPECT_EQ(would_replace,
-            toolbar_model->WouldReplaceSearchURLWithSearchTerms());
+            toolbar_model->WouldReplaceSearchURLWithSearchTerms(false));
+
+  // Now pretend the user started modifying the omnibox.
+  toolbar_model->SetInputInProgress(true);
+  EXPECT_FALSE(toolbar_model->WouldReplaceSearchURLWithSearchTerms(false));
+  EXPECT_EQ(would_replace,
+            toolbar_model->WouldReplaceSearchURLWithSearchTerms(true));
+
+  // Tell the ToolbarModel that the user has stopped editing.  This prevents
+  // this function from having side effects.
+  toolbar_model->SetInputInProgress(false);
 }
 
 
@@ -275,7 +285,8 @@
     const TestItem& test_item = test_items[i];
     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);
   }
 }
 
@@ -294,14 +305,14 @@
   ToolbarModel* toolbar_model = browser()->toolbar_model();
   controller->GetVisibleEntry()->GetSSL().security_style =
       content::SECURITY_STYLE_UNKNOWN;
-  EXPECT_TRUE(toolbar_model->WouldReplaceSearchURLWithSearchTerms());
+  EXPECT_TRUE(toolbar_model->WouldReplaceSearchURLWithSearchTerms(false));
 
   // When done loading, we shouldn't extract search terms if we didn't get an
   // authenticated connection.
   CommitPendingLoad(controller);
   controller->GetVisibleEntry()->GetSSL().security_style =
       content::SECURITY_STYLE_UNKNOWN;
-  EXPECT_FALSE(toolbar_model->WouldReplaceSearchURLWithSearchTerms());
+  EXPECT_FALSE(toolbar_model->WouldReplaceSearchURLWithSearchTerms(false));
 }
 
 // When the Google base URL is overridden on the command line, we should extract
diff --git a/chrome/browser/ui/views/action_box_context_menu.cc b/chrome/browser/ui/views/action_box_context_menu.cc
deleted file mode 100644
index 2beac0b..0000000
--- a/chrome/browser/ui/views/action_box_context_menu.cc
+++ /dev/null
@@ -1,38 +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/views/action_box_context_menu.h"
-
-#include "chrome/browser/ui/toolbar/action_box_context_menu_controller.h"
-#include "ui/gfx/point.h"
-#include "ui/gfx/size.h"
-#include "ui/views/controls/menu/menu_model_adapter.h"
-#include "ui/views/controls/menu/menu_runner.h"
-
-using views::MenuRunner;
-
-ActionBoxContextMenu::ActionBoxContextMenu(
-    Browser* browser,
-    const extensions::Extension* extension)
-    : controller_(browser, extension) {
-}
-
-ActionBoxContextMenu::~ActionBoxContextMenu() {
-}
-
-views::MenuRunner::RunResult ActionBoxContextMenu::RunMenuAt(
-    const gfx::Point& p,
-    views::Widget* parent_widget,
-    ui::MenuSourceType source_type) {
-  adapter_.reset(new views::MenuModelAdapter(controller_.menu_model()));
-  menu_runner_.reset(new MenuRunner(adapter_->CreateMenu()));
-  return menu_runner_->RunMenuAt(
-      parent_widget,
-      NULL,  // No menu button.
-      gfx::Rect(p, gfx::Size()),
-      views::MenuItemView::TOPLEFT,
-      source_type,
-      (MenuRunner::CONTEXT_MENU | MenuRunner::IS_NESTED |
-       MenuRunner::HAS_MNEMONICS));
-}
diff --git a/chrome/browser/ui/views/action_box_context_menu.h b/chrome/browser/ui/views/action_box_context_menu.h
deleted file mode 100644
index 605f40b..0000000
--- a/chrome/browser/ui/views/action_box_context_menu.h
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_VIEWS_ACTION_BOX_CONTEXT_MENU_H__
-#define CHROME_BROWSER_UI_VIEWS_ACTION_BOX_CONTEXT_MENU_H__
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "base/memory/scoped_ptr.h"
-#include "chrome/browser/ui/toolbar/action_box_context_menu_controller.h"
-#include "ui/views/controls/menu/menu_runner.h"
-
-class Browser;
-
-namespace extensions {
-class Extension;
-}  // namespace extensions
-
-namespace gfx {
-class Point;
-}  // namespace gfx
-
-namespace views {
-class MenuModelAdapter;
-class Widget;
-}  // namespace views
-
-// This is the Views class responsible for showing the context menu for
-// extensions in the action box. Actually building and executing commands is
-// handled by ActionBoxContextMenuController.
-class ActionBoxContextMenu {
- public:
-  ActionBoxContextMenu(Browser* browser,
-                       const extensions::Extension* extension);
-  ~ActionBoxContextMenu();
-
-  // See comments in menu_runner.h on how the return value should be used.
-  views::MenuRunner::RunResult RunMenuAt(
-      const gfx::Point& p,
-      views::Widget* parent_widget,
-      ui::MenuSourceType source_type) WARN_UNUSED_RESULT;
-
- private:
-  ActionBoxContextMenuController controller_;
-  scoped_ptr<views::MenuModelAdapter> adapter_;
-  scoped_ptr<views::MenuRunner> menu_runner_;
-
-  DISALLOW_COPY_AND_ASSIGN(ActionBoxContextMenu);
-};
-
-#endif  // CHROME_BROWSER_UI_VIEWS_ACTION_BOX_CONTEXT_MENU_H__
diff --git a/chrome/browser/ui/views/action_box_menu.cc b/chrome/browser/ui/views/action_box_menu.cc
deleted file mode 100644
index d6a7ecd..0000000
--- a/chrome/browser/ui/views/action_box_menu.cc
+++ /dev/null
@@ -1,128 +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/views/action_box_menu.h"
-
-#include "chrome/browser/extensions/extension_icon_image.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/toolbar/action_box_menu_model.h"
-#include "chrome/browser/ui/views/action_box_context_menu.h"
-#include "chrome/common/extensions/api/extension_action/action_info.h"
-#include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/extension_constants.h"
-#include "chrome/common/extensions/manifest_handlers/icons_handler.h"
-#include "ui/views/controls/button/menu_button.h"
-#include "ui/views/controls/image_view.h"
-#include "ui/views/controls/menu/menu_runner.h"
-#include "ui/views/view.h"
-
-using extensions::ActionInfo;
-using extensions::Extension;
-using extensions::IconImage;
-
-namespace {
-class ExtensionImageView : public views::ImageView, public IconImage::Observer {
- public:
-  ExtensionImageView(Profile* profile, const Extension* extension) {
-    const ActionInfo* page_launcher_info =
-        ActionInfo::GetPageLauncherInfo(extension);
-    icon_.reset(new IconImage(profile,
-                              extension,
-                              page_launcher_info->default_icon,
-                              extension_misc::EXTENSION_ICON_ACTION,
-                              extensions::IconsInfo::GetDefaultAppIcon(),
-                              this));
-    SetImage(icon_->image_skia());
-  }
-
- private:
-  virtual void OnExtensionIconImageChanged(
-      extensions::IconImage* image) OVERRIDE {
-    SetImage(icon_->image_skia());
-  }
-
-  scoped_ptr<extensions::IconImage> icon_;
-
-  DISALLOW_COPY_AND_ASSIGN(ExtensionImageView);
-};
-}  // namespace
-
-// static
-scoped_ptr<ActionBoxMenu> ActionBoxMenu::Create(
-    Browser* browser,
-    scoped_ptr<ActionBoxMenuModel> model) {
-  scoped_ptr<ActionBoxMenu> menu(new ActionBoxMenu(browser, model.Pass()));
-  menu->PopulateMenu();
-  return menu.Pass();
-}
-
-ActionBoxMenu::~ActionBoxMenu() {
-}
-
-void ActionBoxMenu::RunMenu(views::MenuButton* menu_button,
-                            gfx::Point menu_offset) {
-  views::View::ConvertPointToScreen(menu_button, &menu_offset);
-  menu_parent_ = menu_button->GetWidget();
-
-  // Ignore the result since we don't need to handle a deleted menu specially.
-  ignore_result(
-      menu_runner_->RunMenuAt(menu_parent_,
-                              menu_button,
-                              gfx::Rect(menu_offset, menu_button->size()),
-                              views::MenuItemView::TOPRIGHT,
-                              ui::MENU_SOURCE_NONE,
-                              views::MenuRunner::HAS_MNEMONICS));
-}
-
-ActionBoxMenu::ActionBoxMenu(Browser* browser,
-                             scoped_ptr<ActionBoxMenuModel> model)
-    : browser_(browser),
-      menu_parent_(NULL),
-      model_(model.Pass()) {
-  views::MenuItemView* menu = new views::MenuItemView(this);
-  menu->set_has_icons(true);
-
-  menu_runner_.reset(new views::MenuRunner(menu));
-}
-
-void ActionBoxMenu::ExecuteCommand(int id) {
-  model_->ExecuteCommand(id);
-}
-
-bool ActionBoxMenu::ShowContextMenu(views::MenuItemView* source,
-                             int id,
-                             const gfx::Point& p,
-                             ui::MenuSourceType source_type) {
-  DCHECK(menu_parent_);
-
-  int index = model_->GetIndexOfCommandId(id);
-  if (!model_->IsItemExtension(index))
-    return false;
-
-  context_menu_.reset(
-      new ActionBoxContextMenu(browser_, model_->GetExtensionAt(index)));
-  if (context_menu_->RunMenuAt(p, menu_parent_, source_type) ==
-      views::MenuRunner::MENU_DELETED)
-    return true;
-  context_menu_.reset();
-  return true;
-}
-
-void ActionBoxMenu::PopulateMenu() {
-  for (int model_index = 0; model_index < model_->GetItemCount();
-       ++model_index) {
-    views::MenuItemView* menu_item =
-        menu_runner_->GetMenu()->AppendMenuItemFromModel(
-            model_.get(), model_index, model_->GetCommandIdAt(model_index));
-    if (model_->GetTypeAt(model_index) == ui::MenuModel::TYPE_COMMAND) {
-      if (model_->IsItemExtension(model_index)) {
-        const Extension* extension = model_->GetExtensionAt(model_index);
-        ExtensionImageView* view = new ExtensionImageView(browser_->profile(),
-                                                          extension);
-        // |menu_item| will own the |view| from now on.
-        menu_item->SetIconView(view);
-      }
-    }
-  }
-}
diff --git a/chrome/browser/ui/views/action_box_menu.h b/chrome/browser/ui/views/action_box_menu.h
deleted file mode 100644
index 3248013..0000000
--- a/chrome/browser/ui/views/action_box_menu.h
+++ /dev/null
@@ -1,58 +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_VIEWS_ACTION_BOX_MENU_H_
-#define CHROME_BROWSER_UI_VIEWS_ACTION_BOX_MENU_H_
-
-#include "base/memory/scoped_ptr.h"
-#include "ui/views/controls/menu/menu_delegate.h"
-
-class ActionBoxContextMenu;
-class ActionBoxMenuModel;
-class Browser;
-
-namespace views {
-class MenuButton;
-class MenuItemView;
-class MenuRunner;
-}
-
-// ActionBoxMenu adapts the ActionBoxMenuModel to view's menu related classes.
-class ActionBoxMenu : public views::MenuDelegate {
- public:
-  // Constructs and initializes an ActionBoxMenu.
-  static scoped_ptr<ActionBoxMenu> Create(Browser* browser,
-                                          scoped_ptr<ActionBoxMenuModel> model);
-
-  virtual ~ActionBoxMenu();
-
-  // Shows the menu relative to the specified button.
-  void RunMenu(views::MenuButton* menu_button, gfx::Point menu_offset);
-
- private:
-  ActionBoxMenu(Browser* browser, scoped_ptr<ActionBoxMenuModel> model);
-
-  // Overridden from views::MenuDelegate:
-  virtual void ExecuteCommand(int id) OVERRIDE;
-  virtual bool ShowContextMenu(views::MenuItemView* source,
-                               int id,
-                               const gfx::Point& p,
-                               ui::MenuSourceType source_type) OVERRIDE;
-
-  // Populates |root_| with all the child menu items from the |model_|.
-  void PopulateMenu();
-
-  Browser* browser_;
-
-  scoped_ptr<ActionBoxContextMenu> context_menu_;
-  scoped_ptr<views::MenuRunner> menu_runner_;
-  views::Widget* menu_parent_;
-
-  // The model that tracks the order of the toolbar icons.
-  scoped_ptr<ActionBoxMenuModel> model_;
-
-  DISALLOW_COPY_AND_ASSIGN(ActionBoxMenu);
-};
-
-#endif  // CHROME_BROWSER_UI_VIEWS_ACTION_BOX_MENU_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 20cc64f..6bbb595 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
@@ -301,20 +301,20 @@
   void AppListClosing();
   void AppListActivationChanged(bool active);
   void ShowAppListDuringModeSwitch(Profile* requested_profile);
-  void DisableAppList();
 
   app_list::AppListView* GetView() { return current_view_; }
 
   // AppListService overrides:
+  virtual void HandleFirstRun() OVERRIDE;
   virtual void Init(Profile* initial_profile) OVERRIDE;
-  virtual void ShowAppList(Profile* requested_profile) OVERRIDE;
+  virtual void ShowForProfile(Profile* requested_profile) OVERRIDE;
   virtual void DismissAppList() OVERRIDE;
   virtual bool IsAppListVisible() const OVERRIDE;
-  virtual void EnableAppList(Profile* initial_profile) OVERRIDE;
   virtual gfx::NativeWindow GetAppListWindow() OVERRIDE;
   virtual AppListControllerDelegate* CreateControllerDelegate() OVERRIDE;
 
   // AppListServiceImpl overrides:
+  virtual void CreateShortcut() OVERRIDE;
   virtual void OnSigninStatusChanged() OVERRIDE;
 
  private:
@@ -388,6 +388,8 @@
   // the right mouse button down, but not if this happens twice in a row.
   bool preserving_focus_for_taskbar_menu_;
 
+  bool enable_app_list_on_next_init_;
+
   base::WeakPtrFactory<AppListController> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(AppListController);
@@ -480,6 +482,7 @@
       can_close_app_list_(true),
       regain_first_lost_focus_(false),
       preserving_focus_for_taskbar_menu_(false),
+      enable_app_list_on_next_init_(false),
       weak_factory_(this) {}
 
 AppListController::~AppListController() {
@@ -500,7 +503,7 @@
     current_view_->OnSigninStatusChanged();
 }
 
-void AppListController::ShowAppList(Profile* requested_profile) {
+void AppListController::ShowForProfile(Profile* requested_profile) {
   DCHECK(requested_profile);
   ScopedKeepAlive show_app_list_keepalive;
 
@@ -527,7 +530,7 @@
     return;
   }
 
-  SaveProfilePathToLocalState(requested_profile->GetPath());
+  SetProfilePath(requested_profile->GetPath());
 
   DismissAppList();
   PopulateViewFromProfile(requested_profile);
@@ -545,7 +548,7 @@
 void AppListController::ShowAppListDuringModeSwitch(
     Profile* requested_profile) {
   regain_first_lost_focus_ = true;
-  ShowAppList(requested_profile);
+  ShowForProfile(requested_profile);
 }
 
 void AppListController::PopulateViewFromProfile(Profile* requested_profile) {
@@ -851,12 +854,28 @@
   current_view_->Prerender();
 }
 
+void AppListController::HandleFirstRun() {
+  PrefService* local_state = g_browser_process->local_state();
+  // If the app list is already enabled during first run, then the user had
+  // opted in to the app launcher before uninstalling, so we re-enable to
+  // restore shortcuts to the app list.
+  // Note we can't directly create the shortcuts here because the IO thread
+  // hasn't been created yet.
+  enable_app_list_on_next_init_ = local_state->GetBoolean(
+      apps::prefs::kAppLauncherHasBeenEnabled);
+}
+
 void AppListController::Init(Profile* initial_profile) {
   // In non-Ash metro mode, we can not show the app list for this process, so do
   // not bother performing Init tasks.
   if (win8::IsSingleWindowMetroMode())
     return;
 
+  if (enable_app_list_on_next_init_) {
+    enable_app_list_on_next_init_ = false;
+    EnableAppList(initial_profile);
+  }
+
   PrefService* prefs = g_browser_process->local_state();
   if (prefs->HasPrefPath(prefs::kRestartWithAppList) &&
       prefs->GetBoolean(prefs::kRestartWithAppList)) {
@@ -893,26 +912,18 @@
   ScheduleWarmup();
 
   MigrateAppLauncherEnabledPref();
-
-  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableAppList))
-    EnableAppList(initial_profile);
-
-  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableAppList))
-    DisableAppList();
+  HandleCommandLineFlags(initial_profile);
 }
 
 bool AppListController::IsAppListVisible() const {
   return current_view_ && current_view_->GetWidget()->IsVisible();
 }
 
-void AppListController::EnableAppList(Profile* initial_profile) {
-  SaveProfilePathToLocalState(initial_profile->GetPath());
+void AppListController::CreateShortcut() {
   // Check if the app launcher shortcuts have ever been created before.
   // Shortcuts should only be created once. If the user unpins the taskbar
   // shortcut, they can restore it by pinning the start menu or desktop
   // shortcut.
-  PrefService* local_state = g_browser_process->local_state();
-  local_state->SetBoolean(apps::prefs::kAppLauncherHasBeenEnabled, true);
   ShellIntegration::ShortcutLocations shortcut_locations;
   shortcut_locations.on_desktop = true;
   shortcut_locations.in_quick_launch_bar = true;
@@ -929,11 +940,6 @@
                   user_data_dir, GetAppModelId(), shortcut_locations));
 }
 
-void AppListController::DisableAppList() {
-  PrefService* local_state = g_browser_process->local_state();
-  local_state->SetBoolean(apps::prefs::kAppLauncherHasBeenEnabled, false);
-}
-
 void AppListController::ScheduleWarmup() {
   // Post a task to create the app list. This is posted to not impact startup
   // time.
diff --git a/chrome/browser/ui/views/autofill/autofill_credit_card_bubble_views.cc b/chrome/browser/ui/views/autofill/autofill_credit_card_bubble_views.cc
index 13f5ae5..4853230 100644
--- a/chrome/browser/ui/views/autofill/autofill_credit_card_bubble_views.cc
+++ b/chrome/browser/ui/views/autofill/autofill_credit_card_bubble_views.cc
@@ -25,18 +25,13 @@
 AutofillCreditCardBubbleViews::~AutofillCreditCardBubbleViews() {}
 
 void AutofillCreditCardBubbleViews::Show() {
-  views::BubbleDelegateView::CreateBubble(this);
   // TODO(dbeam): investigate why this steals focus from the web contents.
+  views::BubbleDelegateView::CreateBubble(this);
 
-  views::BubbleFrameView* frame_view = GetBubbleFrameView();
-  frame_view->SetTitle(controller_->BubbleTitle());
+  GetBubbleFrameView()->SetTitle(controller_->BubbleTitle());
 
-  views::Widget* widget = GetWidget();
-  widget->SetSize(frame_view->GetPreferredSize());
-  // Calls |frame_view_->Layout()| if necessary.
-  frame_view->SetBoundsRect(frame_view->bounds());
-
-  widget->Show();
+  GetWidget()->Show();
+  SizeToContents();
 }
 
 void AutofillCreditCardBubbleViews::Hide() {
diff --git a/chrome/browser/ui/views/autofill/autofill_dialog_views.cc b/chrome/browser/ui/views/autofill/autofill_dialog_views.cc
index a3523a6..29dda7c 100644
--- a/chrome/browser/ui/views/autofill/autofill_dialog_views.cc
+++ b/chrome/browser/ui/views/autofill/autofill_dialog_views.cc
@@ -33,6 +33,7 @@
 #include "ui/gfx/skia_util.h"
 #include "ui/views/background.h"
 #include "ui/views/border.h"
+#include "ui/views/controls/button/blue_button.h"
 #include "ui/views/controls/button/checkbox.h"
 #include "ui/views/controls/button/image_button.h"
 #include "ui/views/controls/button/label_button.h"
@@ -109,6 +110,11 @@
 // Spacing between lines of text in the overlay view.
 const int kOverlayTextInterlineSpacing = 10;
 
+// A dimmer text color used in various parts of the dialog. TODO(estade): should
+// this be part of NativeTheme? Currently the value is duplicated in several
+// places.
+const SkColor kGreyTextColor = SkColorSetRGB(102, 102, 102);
+
 const char kDecoratedTextfieldClassName[] = "autofill/DecoratedTextfield";
 const char kNotificationAreaClassName[] = "autofill/NotificationArea";
 const char kOverlayViewClassName[] = "autofill/OverlayView";
@@ -541,7 +547,7 @@
 AutofillDialogViews::OverlayView::OverlayView(views::ButtonListener* listener)
     : image_view_(new views::ImageView()),
       message_stack_(new views::View()),
-      button_(new views::LabelButton(listener, string16())) {
+      button_(new views::BlueButton(listener, string16())) {
   set_border(views::Border::CreateEmptyBorder(12, 12, 12, 12));
   set_background(views::Background::CreateSolidBackground(GetNativeTheme()->
       GetSystemColor(ui::NativeTheme::kColorId_DialogBackground)));
@@ -556,7 +562,6 @@
       kOverlayTextPadding, kOverlayTextPadding, 0, kOverlayTextPadding));
 
   AddChildView(button_);
-  button_->SetStyle(views::Button::STYLE_NATIVE_TEXTBUTTON);
   button_->set_focusable(true);
 }
 
@@ -640,9 +645,7 @@
     button_->SizeToPreferredSize();
     y -= button_->height();
     button_->SetPosition(gfx::Point(
-        bounds.width() - button_->width() -
-            views::kButtonHEdgeMarginNew,
-        y));
+        bounds.CenterPoint().x() - button_->width() / 2, y));
     y -= views::kButtonVEdgeMarginNew;
   }
 
@@ -1107,6 +1110,8 @@
       web_contents_modal_dialog_manager->delegate()->
           GetWebContentsModalDialogHost());
   web_contents_modal_dialog_manager->ShowDialog(window_->GetNativeView());
+  web_contents_modal_dialog_manager->SetPreventCloseOnLoadStart(
+      window_->GetNativeView(), true);
   focus_manager_ = window_->GetFocusManager();
   focus_manager_->AddFocusChangeListener(this);
 
@@ -1465,6 +1470,10 @@
       controller_->ConfirmButtonText() : controller_->CancelButtonText();
 }
 
+bool AutofillDialogViews::ShouldDefaultButtonBeBlue() const {
+  return true;
+}
+
 bool AutofillDialogViews::IsDialogButtonEnabled(ui::DialogButton button) const {
   return controller_->IsDialogButtonEnabled(button);
 }
@@ -1490,7 +1499,9 @@
       views::Background::CreateSolidBackground(kShadingColor));
 
   legal_document_view_ = new views::StyledLabel(string16(), this);
-  legal_document_view_->SetDisplayedOnBackgroundColor(kShadingColor);
+  views::StyledLabel::RangeStyleInfo default_style;
+  default_style.color = kGreyTextColor;
+  legal_document_view_->SetDefaultStyle(default_style);
 
   footnote_view_->AddChildView(legal_document_view_);
   footnote_view_->SetVisible(false);
@@ -1503,17 +1514,15 @@
 }
 
 bool AutofillDialogViews::Cancel() {
-  controller_->OnCancel();
-  return true;
+  return controller_->OnCancel();
 }
 
 bool AutofillDialogViews::Accept() {
   if (ValidateForm())
-    controller_->OnAccept();
-  else if (!validity_map_.empty())
-    validity_map_.begin()->first->RequestFocus();
+    return controller_->OnAccept();
 
-  // |controller_| decides when to hide the dialog.
+  if (!validity_map_.empty())
+    validity_map_.begin()->first->RequestFocus();
   return false;
 }
 
@@ -1961,8 +1970,10 @@
 
   std::map<views::View*, string16>::iterator error_message =
       validity_map_.find(view);
-  if (error_message != validity_map_.end())
+  if (error_message != validity_map_.end()) {
+    view->ScrollRectToVisible(view->GetLocalBounds());
     error_bubble_.reset(new ErrorBubble(view, error_message->second));
+  }
 }
 
 void AutofillDialogViews::MarkInputsInvalid(DialogSection section,
diff --git a/chrome/browser/ui/views/autofill/autofill_dialog_views.h b/chrome/browser/ui/views/autofill/autofill_dialog_views.h
index 626d21a..cae7ce1 100644
--- a/chrome/browser/ui/views/autofill/autofill_dialog_views.h
+++ b/chrome/browser/ui/views/autofill/autofill_dialog_views.h
@@ -123,6 +123,7 @@
   virtual views::View* CreateOverlayView() OVERRIDE;
   virtual int GetDialogButtons() const OVERRIDE;
   virtual string16 GetDialogButtonLabel(ui::DialogButton button) const OVERRIDE;
+  virtual bool ShouldDefaultButtonBeBlue() const OVERRIDE;
   virtual bool IsDialogButtonEnabled(ui::DialogButton button) const OVERRIDE;
   virtual views::View* CreateExtraView() OVERRIDE;
   virtual views::View* CreateTitlebarExtraView() OVERRIDE;
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bubble_view.cc b/chrome/browser/ui/views/bookmarks/bookmark_bubble_view.cc
index ca52a45..86b9060 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_bubble_view.cc
+++ b/chrome/browser/ui/views/bookmarks/bookmark_bubble_view.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/ui/views/bookmarks/bookmark_bubble_view.h"
 
+#include "base/command_line.h"
 #include "base/strings/string16.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
@@ -13,9 +14,10 @@
 #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/sync/sync_promo_ui.h"
 #include "chrome/browser/ui/views/bookmarks/bookmark_bubble_view_observer.h"
+#include "chrome/browser/ui/views/bookmarks/bookmark_sync_promo_view.h"
+#include "chrome/common/chrome_switches.h"
 #include "content/public/browser/user_metrics.h"
 #include "grit/generated_resources.h"
 #include "grit/theme_resources.h"
@@ -41,6 +43,9 @@
 // Minimum width of the the bubble.
 const int kMinBubbleWidth = 350;
 
+// Width of the border of a button.
+const int kControlBorderWidth = 2;
+
 }  // namespace
 
 // Declared in browser_dialogs.h so callers don't have to depend on our header.
@@ -49,10 +54,15 @@
 
 void ShowBookmarkBubbleView(views::View* anchor_view,
                             BookmarkBubbleViewObserver* observer,
+                            scoped_ptr<BookmarkBubbleDelegate> delegate,
                             Profile* profile,
                             const GURL& url,
                             bool newly_bookmarked) {
-  BookmarkBubbleView::ShowBubble(anchor_view, observer, profile, url,
+  BookmarkBubbleView::ShowBubble(anchor_view,
+                                 observer,
+                                 delegate.Pass(),
+                                 profile,
+                                 url,
                                  newly_bookmarked);
 }
 
@@ -71,15 +81,21 @@
 BookmarkBubbleView* BookmarkBubbleView::bookmark_bubble_ = NULL;
 
 // static
-void BookmarkBubbleView::ShowBubble(views::View* anchor_view,
-                                    BookmarkBubbleViewObserver* observer,
-                                    Profile* profile,
-                                    const GURL& url,
-                                    bool newly_bookmarked) {
+void BookmarkBubbleView::ShowBubble(
+    views::View* anchor_view,
+    BookmarkBubbleViewObserver* observer,
+    scoped_ptr<BookmarkBubbleDelegate> delegate,
+    Profile* profile,
+    const GURL& url,
+    bool newly_bookmarked) {
   if (IsShowing())
     return;
 
-  bookmark_bubble_ = new BookmarkBubbleView(anchor_view, observer, profile, url,
+  bookmark_bubble_ = new BookmarkBubbleView(anchor_view,
+                                            observer,
+                                            delegate.Pass(),
+                                            profile,
+                                            url,
                                             newly_bookmarked);
   views::BubbleDelegateView::CreateBubble(bookmark_bubble_)->Show();
   // Select the entire title textfield contents when the bubble is first shown.
@@ -123,7 +139,7 @@
 
   if (observer_)
     observer_->OnBookmarkBubbleHidden();
- }
+}
 
 bool BookmarkBubbleView::AcceleratorPressed(
     const ui::Accelerator& accelerator) {
@@ -172,14 +188,22 @@
   GridLayout* layout = new GridLayout(this);
   SetLayoutManager(layout);
 
-  const int kTitleColumnSetID = 0;
-  ColumnSet* cs = layout->AddColumnSet(kTitleColumnSetID);
+  // Column sets used in the layout of the bubble.
+  enum ColumnSetID {
+    TITLE_COLUMN_SET_ID,
+    CONTENT_COLUMN_SET_ID,
+    SYNC_PROMO_COLUMN_SET_ID
+  };
+
+  ColumnSet* cs = layout->AddColumnSet(TITLE_COLUMN_SET_ID);
+  cs->AddPaddingColumn(0, views::kButtonHEdgeMarginNew);
   cs->AddColumn(GridLayout::CENTER, GridLayout::CENTER, 0, GridLayout::USE_PREF,
                 0, 0);
+  cs->AddPaddingColumn(0, views::kButtonHEdgeMarginNew);
 
   // The column layout used for middle and bottom rows.
-  const int kFirstColumnSetID = 1;
-  cs = layout->AddColumnSet(kFirstColumnSetID);
+  cs = layout->AddColumnSet(CONTENT_COLUMN_SET_ID);
+  cs->AddPaddingColumn(0, views::kButtonHEdgeMarginNew);
   cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 0,
                 GridLayout::USE_PREF, 0, 0);
   cs->AddPaddingColumn(0, views::kUnrelatedControlHorizontalSpacing);
@@ -193,12 +217,13 @@
   cs->AddPaddingColumn(0, views::kRelatedButtonHSpacing);
   cs->AddColumn(GridLayout::LEADING, GridLayout::TRAILING, 0,
                 GridLayout::USE_PREF, 0, 0);
+  cs->AddPaddingColumn(0, views::kButtonHEdgeMarginNew);
 
-  layout->StartRow(0, kTitleColumnSetID);
+  layout->StartRow(0, TITLE_COLUMN_SET_ID);
   layout->AddView(title_label);
   layout->AddPaddingRow(0, views::kUnrelatedControlHorizontalSpacing);
 
-  layout->StartRow(0, kFirstColumnSetID);
+  layout->StartRow(0, CONTENT_COLUMN_SET_ID);
   views::Label* label = new views::Label(
       l10n_util::GetStringUTF16(IDS_BOOKMARK_BUBBLE_TITLE_TEXT));
   layout->AddView(label);
@@ -208,28 +233,52 @@
 
   layout->AddPaddingRow(0, views::kUnrelatedControlHorizontalSpacing);
 
-  layout->StartRow(0, kFirstColumnSetID);
+  layout->StartRow(0, CONTENT_COLUMN_SET_ID);
   layout->AddView(combobox_label);
   layout->AddView(parent_combobox_, 5, 1);
 
   layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
 
-  layout->StartRow(0, kFirstColumnSetID);
+  layout->StartRow(0, CONTENT_COLUMN_SET_ID);
   layout->SkipColumns(2);
   layout->AddView(remove_button_);
   layout->AddView(edit_button_);
   layout->AddView(close_button_);
 
+  layout->AddPaddingRow(
+      0,
+      views::kUnrelatedControlVerticalSpacing - kControlBorderWidth);
+
+  const CommandLine* command_line = CommandLine::ForCurrentProcess();
+  if (command_line->HasSwitch(switches::kEnableBookmarkSyncPromo) &&
+      SyncPromoUI::ShouldShowSyncPromo(profile_)) {
+    // The column layout used for the sync promo.
+    cs = layout->AddColumnSet(SYNC_PROMO_COLUMN_SET_ID);
+    cs->AddColumn(GridLayout::FILL,
+                  GridLayout::FILL,
+                  1,
+                  GridLayout::USE_PREF,
+                  0,
+                  0);
+    layout->StartRow(0, SYNC_PROMO_COLUMN_SET_ID);
+
+    sync_promo_view_ = new BookmarkSyncPromoView(delegate_.get());
+    layout->AddView(sync_promo_view_);
+  }
+
   AddAccelerator(ui::Accelerator(ui::VKEY_RETURN, ui::EF_NONE));
 }
 
-BookmarkBubbleView::BookmarkBubbleView(views::View* anchor_view,
-                                       BookmarkBubbleViewObserver* observer,
-                                       Profile* profile,
-                                       const GURL& url,
-                                       bool newly_bookmarked)
+BookmarkBubbleView::BookmarkBubbleView(
+    views::View* anchor_view,
+    BookmarkBubbleViewObserver* observer,
+    scoped_ptr<BookmarkBubbleDelegate> delegate,
+    Profile* profile,
+    const GURL& url,
+    bool newly_bookmarked)
     : BubbleDelegateView(anchor_view, views::BubbleBorder::TOP_RIGHT),
       observer_(observer),
+      delegate_(delegate.Pass()),
       profile_(profile),
       url_(url),
       newly_bookmarked_(newly_bookmarked),
@@ -242,13 +291,14 @@
       close_button_(NULL),
       title_tf_(NULL),
       parent_combobox_(NULL),
+      sync_promo_view_(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));
+  set_margins(gfx::Insets(views::kPanelVertMargin, 0, 0, 0));
   // Compensate for built-in vertical padding in the anchor view's image.
   set_anchor_view_insets(gfx::Insets(7, 0, 7, 0));
 }
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bubble_view.h b/chrome/browser/ui/views/bookmarks/bookmark_bubble_view.h
index da03710..82cdfa9 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_bubble_view.h
+++ b/chrome/browser/ui/views/bookmarks/bookmark_bubble_view.h
@@ -7,7 +7,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/bookmarks/bookmark_bubble_delegate.h"
 #include "chrome/browser/ui/bookmarks/recently_used_folders_combo_model.h"
 #include "ui/views/bubble/bubble_delegate.h"
 #include "ui/views/controls/button/button.h"
@@ -32,6 +35,7 @@
  public:
   static void ShowBubble(views::View* anchor_view,
                          BookmarkBubbleViewObserver* observer,
+                         scoped_ptr<BookmarkBubbleDelegate> delegate,
                          Profile* profile,
                          const GURL& url,
                          bool newly_bookmarked);
@@ -56,9 +60,14 @@
   virtual void Init() OVERRIDE;
 
  private:
+  friend class BookmarkBubbleViewTest;
+  FRIEND_TEST_ALL_PREFIXES(BookmarkBubbleViewTest, SyncPromoSignedIn);
+  FRIEND_TEST_ALL_PREFIXES(BookmarkBubbleViewTest, SyncPromoNotSignedIn);
+
   // Creates a BookmarkBubbleView.
   BookmarkBubbleView(views::View* anchor_view,
                      BookmarkBubbleViewObserver* observer,
+                     scoped_ptr<BookmarkBubbleDelegate> delegate,
                      Profile* profile,
                      const GURL& url,
                      bool newly_bookmarked);
@@ -92,6 +101,9 @@
   // Our observer, to notify when the bubble shows or hides.
   BookmarkBubbleViewObserver* observer_;
 
+  // Delegate, to handle clicks on the sign in link.
+  scoped_ptr<BookmarkBubbleDelegate> delegate_;
+
   // The profile.
   Profile* profile_;
 
@@ -119,6 +131,9 @@
   // the current parent.
   views::Combobox* parent_combobox_;
 
+  // Bookmark sync promo view, if displayed.
+  views::View* sync_promo_view_;
+
   // When the destructor is invoked should the bookmark be removed?
   bool remove_bookmark_;
 
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bubble_view_unittest.cc b/chrome/browser/ui/views/bookmarks/bookmark_bubble_view_unittest.cc
new file mode 100644
index 0000000..1809017
--- /dev/null
+++ b/chrome/browser/ui/views/bookmarks/bookmark_bubble_view_unittest.cc
@@ -0,0 +1,110 @@
+// Copyright 2013 The Chromium Authors. 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_bubble_view.h"
+
+#include <string>
+
+#include "base/command_line.h"
+#include "base/memory/scoped_ptr.h"
+#include "chrome/browser/bookmarks/bookmark_model_factory.h"
+#include "chrome/browser/bookmarks/bookmark_utils.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/ui/bookmarks/bookmark_bubble_delegate.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/test/base/browser_with_test_window_test.h"
+#include "chrome/test/base/ui_test_utils.h"
+
+namespace {
+const char kTestBookmarkURL[] = "http://www.google.com";
+} // namespace
+
+class BookmarkBubbleViewTest : public BrowserWithTestWindowTest {
+ public:
+  BookmarkBubbleViewTest() {}
+
+  // testing::Test:
+  virtual void SetUp() OVERRIDE {
+    BrowserWithTestWindowTest::SetUp();
+
+    CommandLine* command_line = CommandLine::ForCurrentProcess();
+    command_line->AppendSwitch(switches::kEnableBookmarkSyncPromo);
+
+    profile()->CreateBookmarkModel(true);
+    ui_test_utils::WaitForBookmarkModelToLoad(profile());
+
+    bookmark_utils::AddIfNotBookmarked(
+        BookmarkModelFactory::GetForProfile(profile()),
+        GURL(kTestBookmarkURL),
+        string16());
+  }
+
+  virtual void TearDown() OVERRIDE {
+    // Make sure the bubble is destroyed before the profile to avoid a crash.
+    bubble_.reset();
+
+    BrowserWithTestWindowTest::TearDown();
+  }
+
+ protected:
+  // Creates a bookmark bubble view.
+  void CreateBubbleView() {
+    scoped_ptr<BookmarkBubbleDelegate> delegate;
+    bubble_.reset(new BookmarkBubbleView(NULL,
+                                         NULL,
+                                         delegate.Pass(),
+                                         profile(),
+                                         GURL(kTestBookmarkURL),
+                                         true));
+  }
+
+  void CreateSigninManager(const std::string& username) {
+    SigninManagerBase* signin_manager =
+        static_cast<SigninManagerBase*>(
+            SigninManagerFactory::GetInstance()->SetTestingFactoryAndUse(
+                profile(),
+                &BookmarkBubbleViewTest::BuildFakeSignInManager));
+    signin_manager->Initialize(profile(), NULL);
+
+    if (!username.empty()) {
+      ASSERT_TRUE(signin_manager);
+      signin_manager->SetAuthenticatedUsername(username);
+    }
+  }
+
+  scoped_ptr<BookmarkBubbleView> bubble_;
+
+ private:
+  static BrowserContextKeyedService* BuildFakeSignInManager(
+      content::BrowserContext* profile) {
+#if defined(OS_CHROMEOS)
+    return new FakeSigninManagerBase();
+#else  // !defined(OS_CHROMEOS)
+    return new FakeSigninManager(static_cast<Profile*>(profile));
+#endif
+  }
+
+  DISALLOW_COPY_AND_ASSIGN(BookmarkBubbleViewTest);
+};
+
+// Verifies that the sync promo is not displayed for a signed in user.
+TEST_F(BookmarkBubbleViewTest, SyncPromoSignedIn) {
+  CreateSigninManager("fake_username");
+  CreateBubbleView();
+  bubble_->Init();
+  EXPECT_FALSE(bubble_->sync_promo_view_);
+}
+
+// Verifies that the sync promo is displayed for a user that is not signed in.
+TEST_F(BookmarkBubbleViewTest, SyncPromoNotSignedIn) {
+  CreateBubbleView();
+  bubble_->Init();
+#if defined(OS_CHROMEOS)
+  EXPECT_FALSE(bubble_->sync_promo_view_);
+#else  // !defined(OS_CHROMEOS)
+  EXPECT_TRUE(bubble_->sync_promo_view_);
+#endif
+}
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_sync_promo_view.cc b/chrome/browser/ui/views/bookmarks/bookmark_sync_promo_view.cc
new file mode 100644
index 0000000..ef722e8
--- /dev/null
+++ b/chrome/browser/ui/views/bookmarks/bookmark_sync_promo_view.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/ui/views/bookmarks/bookmark_sync_promo_view.h"
+
+#include "base/strings/string16.h"
+#include "chrome/browser/ui/bookmarks/bookmark_bubble_delegate.h"
+#include "grit/generated_resources.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/gfx/font.h"
+#include "ui/views/background.h"
+#include "ui/views/border.h"
+#include "ui/views/controls/styled_label.h"
+#include "ui/views/layout/box_layout.h"
+#include "ui/views/layout/layout_constants.h"
+
+namespace {
+// Background color of the promo.
+const SkColor kBackgroundColor = SkColorSetRGB(245, 245, 245);
+
+// Color of the top border of the promo.
+const SkColor kBorderColor = SkColorSetRGB(229, 229, 229);
+
+// Width of the top border of the promo.
+const int kBorderWidth = 1;
+
+// Color of the text of the promo.
+const SkColor kTextColor = SkColorSetRGB(102, 102, 102);
+
+}  // namespace
+
+BookmarkSyncPromoView::BookmarkSyncPromoView(BookmarkBubbleDelegate* delegate)
+    : delegate_(delegate) {
+  set_background(views::Background::CreateSolidBackground(kBackgroundColor));
+  set_border(views::Border::CreateSolidSidedBorder(kBorderWidth,
+                                                   0,
+                                                   0,
+                                                   0,
+                                                   kBorderColor));
+  size_t offset;
+  string16 link_text = l10n_util::GetStringUTF16(IDS_BOOKMARK_SYNC_PROMO_LINK);
+  string16 promo_text = l10n_util::GetStringFUTF16(
+      IDS_BOOKMARK_SYNC_PROMO_MESSAGE,
+      link_text,
+      &offset);
+
+  views::StyledLabel* promo_label = new views::StyledLabel(promo_text, this);
+  promo_label->SetDisplayedOnBackgroundColor(kBackgroundColor);
+
+  views::StyledLabel::RangeStyleInfo link_style =
+      views::StyledLabel::RangeStyleInfo::CreateForLink();
+  link_style.font_style = gfx::Font::NORMAL;
+  promo_label->AddStyleRange(ui::Range(offset, offset + link_text.length()),
+                             link_style);
+
+  views::StyledLabel::RangeStyleInfo promo_style;
+  promo_style.color = kTextColor;
+  ui::Range before_link_range(0, offset);
+  if (!before_link_range.is_empty())
+    promo_label->AddStyleRange(before_link_range, promo_style);
+  ui::Range after_link_range(offset + link_text.length(), promo_text.length());
+  if (!after_link_range.is_empty())
+    promo_label->AddStyleRange(after_link_range, promo_style);
+
+  views::BoxLayout* layout = new views::BoxLayout(views::BoxLayout::kVertical,
+                                                  views::kButtonHEdgeMarginNew,
+                                                  views::kPanelVertMargin,
+                                                  0);
+  SetLayoutManager(layout);
+  AddChildView(promo_label);
+}
+
+void BookmarkSyncPromoView::StyledLabelLinkClicked(const ui::Range& range,
+                                                   int event_flags) {
+  delegate_->OnSignInLinkClicked();
+}
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_sync_promo_view.h b/chrome/browser/ui/views/bookmarks/bookmark_sync_promo_view.h
new file mode 100644
index 0000000..deb37a1
--- /dev/null
+++ b/chrome/browser/ui/views/bookmarks/bookmark_sync_promo_view.h
@@ -0,0 +1,33 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_VIEWS_BOOKMARKS_BOOKMARK_SYNC_PROMO_VIEW_H_
+#define CHROME_BROWSER_UI_VIEWS_BOOKMARKS_BOOKMARK_SYNC_PROMO_VIEW_H_
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "ui/views/controls/styled_label_listener.h"
+#include "ui/views/view.h"
+
+class BookmarkBubbleDelegate;
+
+// Bookmark sync promo displayed at the bottom of the bookmark bubble.
+class BookmarkSyncPromoView : public views::StyledLabelListener,
+                              public views::View {
+ public:
+  // |delegate| is not owned by BookmarkSyncPromoView.
+  explicit BookmarkSyncPromoView(BookmarkBubbleDelegate* delegate);
+
+ private:
+  // views::StyledLabelListener:
+  virtual void StyledLabelLinkClicked(const ui::Range& range,
+                                      int event_flags) OVERRIDE;
+
+  // Delegate, to handle clicks on the sign in link.
+  BookmarkBubbleDelegate* delegate_;
+
+  DISALLOW_COPY_AND_ASSIGN(BookmarkSyncPromoView);
+};
+
+#endif  // CHROME_BROWSER_UI_VIEWS_BOOKMARKS_BOOKMARK_SYNC_PROMO_VIEW_H_
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_sync_promo_view_unittest.cc b/chrome/browser/ui/views/bookmarks/bookmark_sync_promo_view_unittest.cc
new file mode 100644
index 0000000..34ee686
--- /dev/null
+++ b/chrome/browser/ui/views/bookmarks/bookmark_sync_promo_view_unittest.cc
@@ -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.
+
+#include "chrome/browser/ui/views/bookmarks/bookmark_sync_promo_view.h"
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
+#include "chrome/browser/ui/bookmarks/bookmark_bubble_delegate.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/events/event_constants.h"
+#include "ui/base/range/range.h"
+
+class BookmarkSyncPromoViewTest : public BookmarkBubbleDelegate,
+                                  public testing::Test {
+ public:
+  BookmarkSyncPromoViewTest() : sign_in_clicked_count_(0) {}
+
+ protected:
+  // BookmarkBubbleDelegate:
+  virtual void OnSignInLinkClicked() OVERRIDE {
+    ++sign_in_clicked_count_;
+  }
+
+  // Number of times that OnSignInLinkClicked has been called.
+  int sign_in_clicked_count_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(BookmarkSyncPromoViewTest);
+};
+
+TEST_F(BookmarkSyncPromoViewTest, SignInLink) {
+  scoped_ptr<BookmarkSyncPromoView> sync_promo;
+  sync_promo.reset(new BookmarkSyncPromoView(this));
+
+  // Simulate clicking the "Sign in" link.
+  views::StyledLabelListener* listener = sync_promo.get();
+  listener->StyledLabelLinkClicked(ui::Range(), ui::EF_NONE);
+
+  EXPECT_EQ(1, sign_in_clicked_count_);
+}
diff --git a/chrome/browser/ui/views/browser_dialogs.h b/chrome/browser/ui/views/browser_dialogs.h
index 2dd992e..30d12a5 100644
--- a/chrome/browser/ui/views/browser_dialogs.h
+++ b/chrome/browser/ui/views/browser_dialogs.h
@@ -5,6 +5,7 @@
 #ifndef CHROME_BROWSER_UI_VIEWS_BROWSER_DIALOGS_H_
 #define CHROME_BROWSER_UI_VIEWS_BROWSER_DIALOGS_H_
 
+#include "base/memory/scoped_ptr.h"
 #include "ui/gfx/native_widget_types.h"
 
 // This file contains functions for running a variety of browser dialogs and
@@ -14,6 +15,7 @@
 // TODO: Make as many of these methods as possible cross platform, and move them
 // into chrome/browser/ui/browser_dialogs.h.
 
+class BookmarkBubbleDelegate;
 class BookmarkBubbleViewObserver;
 class Browser;
 class BrowserView;
@@ -36,6 +38,7 @@
 // Shows or hides the bookmark bubble anchored to the supplied view.
 void ShowBookmarkBubbleView(views::View* anchor_view,
                             BookmarkBubbleViewObserver* observer,
+                            scoped_ptr<BookmarkBubbleDelegate> delegate,
                             Profile* profile,
                             const GURL& url,
                             bool newly_bookmarked);
diff --git a/chrome/browser/ui/views/collected_cookies_views.cc b/chrome/browser/ui/views/collected_cookies_views.cc
index 4024245..3e602b4 100644
--- a/chrome/browser/ui/views/collected_cookies_views.cc
+++ b/chrome/browser/ui/views/collected_cookies_views.cc
@@ -332,7 +332,7 @@
   layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
 
   layout->StartRow(0, single_column_layout_id);
-  cookie_info_view_ = new CookieInfoView(false);
+  cookie_info_view_ = new CookieInfoView();
   layout->AddView(cookie_info_view_);
   layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
 
diff --git a/chrome/browser/ui/views/cookie_info_view.cc b/chrome/browser/ui/views/cookie_info_view.cc
index ad0bea2..7cef982 100644
--- a/chrome/browser/ui/views/cookie_info_view.cc
+++ b/chrome/browser/ui/views/cookie_info_view.cc
@@ -20,7 +20,6 @@
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/color_utils.h"
 #include "ui/views/border.h"
-#include "ui/views/controls/combobox/combobox.h"
 #include "ui/views/controls/label.h"
 #include "ui/views/controls/textfield/textfield.h"
 #include "ui/views/layout/grid_layout.h"
@@ -37,7 +36,7 @@
 ///////////////////////////////////////////////////////////////////////////////
 // CookieInfoView, public:
 
-CookieInfoView::CookieInfoView(bool editable_expiration_date)
+CookieInfoView::CookieInfoView()
     : name_label_(NULL),
       name_value_field_(NULL),
       content_label_(NULL),
@@ -51,11 +50,7 @@
       created_label_(NULL),
       created_value_field_(NULL),
       expires_label_(NULL),
-      expires_value_field_(NULL),
-      expires_value_combobox_(NULL),
-      expire_view_(NULL),
-      editable_expiration_date_(editable_expiration_date),
-      delegate_(NULL) {
+      expires_value_field_(NULL) {
 }
 
 CookieInfoView::~CookieInfoView() {
@@ -74,20 +69,7 @@
       base::TimeFormatFriendlyDateAndTime(cookie.ExpiryDate()) :
       l10n_util::GetStringUTF16(IDS_COOKIES_COOKIE_EXPIRES_SESSION);
 
-  if (editable_expiration_date_) {
-    expire_combo_values_.clear();
-    if (cookie.IsPersistent())
-      expire_combo_values_.push_back(expire_text);
-    expire_combo_values_.push_back(
-        l10n_util::GetStringUTF16(IDS_COOKIES_COOKIE_EXPIRES_SESSION));
-    expires_value_combobox_->ModelChanged();
-    expires_value_combobox_->SetSelectedIndex(0);
-    expires_value_combobox_->SetEnabled(true);
-    expires_value_combobox_->set_listener(this);
-  } else {
-    expires_value_field_->SetText(expire_text);
-  }
-
+  expires_value_field_->SetText(expire_text);
   send_for_value_field_->SetText(cookie.IsSecure() ?
       l10n_util::GetStringUTF16(IDS_COOKIES_COOKIE_SENDFOR_SECURE) :
       l10n_util::GetStringUTF16(IDS_COOKIES_COOKIE_SENDFOR_ANY));
@@ -112,8 +94,7 @@
   path_value_field_->SetText(no_cookie_string);
   send_for_value_field_->SetText(no_cookie_string);
   created_value_field_->SetText(no_cookie_string);
-  if (expires_value_field_)
-    expires_value_field_->SetText(no_cookie_string);
+  expires_value_field_->SetText(no_cookie_string);
   EnableCookieDisplay(false);
 }
 
@@ -124,8 +105,7 @@
   path_value_field_->SetEnabled(enabled);
   send_for_value_field_->SetEnabled(enabled);
   created_value_field_->SetEnabled(enabled);
-  if (expires_value_field_)
-    expires_value_field_->SetEnabled(enabled);
+  expires_value_field_->SetEnabled(enabled);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -137,25 +117,6 @@
     Init();
 }
 
-///////////////////////////////////////////////////////////////////////////////
-// CookieInfoView, views::ComboboxListener overrides.
-
-void CookieInfoView::OnSelectedIndexChanged(views::Combobox* combobox) {
-  DCHECK_EQ(combobox, expires_value_combobox_);
-  if (delegate_)
-    delegate_->ModifyExpireDate(combobox->selected_index() != 0);
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// CookieInfoView, ui::ComboboxModel overrides.
-int CookieInfoView::GetItemCount() const {
-  return static_cast<int>(expire_combo_values_.size());
-}
-
-string16 CookieInfoView::GetItemAt(int index) {
-  return expire_combo_values_[index];
-}
-
 void CookieInfoView::AddLabelRow(int layout_id, views::GridLayout* layout,
                                  views::View* label, views::View* value) {
   layout->StartRow(0, layout_id);
@@ -206,10 +167,7 @@
   created_value_field_ = new views::Textfield;
   expires_label_ = new views::Label(
       l10n_util::GetStringUTF16(IDS_COOKIES_COOKIE_EXPIRES_LABEL));
-  if (editable_expiration_date_)
-    expires_value_combobox_ = new views::Combobox(this);
-  else
-    expires_value_field_ = new views::Textfield;
+  expires_value_field_ = new views::Textfield;
 
   using views::GridLayout;
   using views::ColumnSet;
@@ -248,14 +206,8 @@
               send_for_value_field_);
   AddLabelRow(three_column_layout_id, layout, created_label_,
               created_value_field_);
-
-  if (editable_expiration_date_) {
-    AddControlRow(three_column_layout_id, layout, expires_label_,
-                  expires_value_combobox_);
-  } else {
-    AddLabelRow(three_column_layout_id, layout, expires_label_,
-                expires_value_field_);
-  }
+  AddLabelRow(three_column_layout_id, layout, expires_label_,
+              expires_value_field_);
 
   // Color these borderless text areas the same as the containing dialog.
 #if defined(USE_AURA) || !defined(OS_WIN)
@@ -282,9 +234,7 @@
   created_value_field_->SetReadOnly(true);
   created_value_field_->RemoveBorder();
   created_value_field_->SetBackgroundColor(text_area_background);
-  if (expires_value_field_) {
-    expires_value_field_->SetReadOnly(true);
-    expires_value_field_->RemoveBorder();
-    expires_value_field_->SetBackgroundColor(text_area_background);
-  }
+  expires_value_field_->SetReadOnly(true);
+  expires_value_field_->RemoveBorder();
+  expires_value_field_->SetBackgroundColor(text_area_background);
 }
diff --git a/chrome/browser/ui/views/cookie_info_view.h b/chrome/browser/ui/views/cookie_info_view.h
index 82a3de2..bcf9219 100644
--- a/chrome/browser/ui/views/cookie_info_view.h
+++ b/chrome/browser/ui/views/cookie_info_view.h
@@ -11,8 +11,6 @@
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
 #include "base/strings/string16.h"
-#include "ui/base/models/combobox_model.h"
-#include "ui/views/controls/combobox/combobox_listener.h"
 #include "ui/views/view.h"
 
 namespace views {
@@ -26,25 +24,12 @@
 }
 
 ///////////////////////////////////////////////////////////////////////////////
-// CookieInfoViewDelegate
-//
-class CookieInfoViewDelegate {
- public:
-  virtual void ModifyExpireDate(bool session_expire) = 0;
-
- protected:
-  virtual ~CookieInfoViewDelegate() {}
-};
-
-///////////////////////////////////////////////////////////////////////////////
 // CookieInfoView
 //
 //  Responsible for displaying a tabular grid of Cookie information.
-class CookieInfoView : public views::View,
-                       public views::ComboboxListener,
-                       public ui::ComboboxModel {
+class CookieInfoView : public views::View {
  public:
-  explicit CookieInfoView(bool editable_expiration_date);
+  CookieInfoView();
   virtual ~CookieInfoView();
 
   // Update the display from the specified CookieNode.
@@ -61,20 +46,11 @@
   // Enables or disables the cookie property text fields.
   void EnableCookieDisplay(bool enabled);
 
-  void set_delegate(CookieInfoViewDelegate* delegate) { delegate_ = delegate; }
-
  protected:
   // views::View:
   virtual void ViewHierarchyChanged(
       const ViewHierarchyChangedDetails& details) OVERRIDE;
 
-  // views::ComboboxListener:
-  virtual void OnSelectedIndexChanged(views::Combobox* combobox) OVERRIDE;
-
-  // ui::ComboboxModel:
-  virtual int GetItemCount() const OVERRIDE;
-  virtual string16 GetItemAt(int index) OVERRIDE;
-
  private:
   // Layout helper routines.
   void AddLabelRow(int layout_id, views::GridLayout* layout,
@@ -100,20 +76,6 @@
   views::Textfield* created_value_field_;
   views::Label* expires_label_;
   views::Textfield* expires_value_field_;
-  views::Combobox* expires_value_combobox_;
-  views::View* expire_view_;
-
-  // Option values for expires_value_combobox_.
-  std::vector<string16> expire_combo_values_;
-
-  // True if expiration date can be edited. In this case we will show
-  // expires_value_combobox_ instead of expires_value_field_. The cookie's
-  // expiration date is editable only this class is used in
-  // CookiesPromptView (alert before cookie is set), in all other cases we
-  // don't let user directly change cookie setting.
-  bool editable_expiration_date_;
-
-  CookieInfoViewDelegate* delegate_;
 
   DISALLOW_COPY_AND_ASSIGN(CookieInfoView);
 };
diff --git a/chrome/browser/ui/views/download/download_item_view.cc b/chrome/browser/ui/views/download/download_item_view.cc
index 4977edf..11561a0 100644
--- a/chrome/browser/ui/views/download/download_item_view.cc
+++ b/chrome/browser/ui/views/download/download_item_view.cc
@@ -30,7 +30,7 @@
 #include "content/public/browser/download_danger_type.h"
 #include "grit/generated_resources.h"
 #include "grit/theme_resources.h"
-#include "third_party/icu/public/common/unicode/uchar.h"
+#include "third_party/icu/source/common/unicode/uchar.h"
 #include "ui/base/accessibility/accessible_view_state.h"
 #include "ui/base/animation/slide_animation.h"
 #include "ui/base/events/event.h"
@@ -907,7 +907,8 @@
 
   // If |is_mouse_gesture| is false, |p| is ignored. The menu is shown aligned
   // to drop down arrow button.
-  if (!source_type == ui::MENU_SOURCE_MOUSE) {
+  if (source_type != ui::MENU_SOURCE_MOUSE &&
+      source_type != ui::MENU_SOURCE_TOUCH) {
     drop_down_pressed_ = true;
     SetState(NORMAL, PUSHED);
     point.SetPoint(drop_down_x_left_, box_y_);
diff --git a/chrome/browser/ui/views/extensions/shell_window_frame_view.cc b/chrome/browser/ui/views/extensions/shell_window_frame_view.cc
index c2e0e94..f346e65 100644
--- a/chrome/browser/ui/views/extensions/shell_window_frame_view.cc
+++ b/chrome/browser/ui/views/extensions/shell_window_frame_view.cc
@@ -194,21 +194,19 @@
   bool can_ever_resize = frame_->widget_delegate() ?
       frame_->widget_delegate()->CanResize() :
       false;
-  if (can_ever_resize) {
-    // Don't allow overlapping resize handles when the window is maximized or
-    // fullscreen, as it can't be resized in those states.
-    int resize_border =
-        frame_->IsMaximized() || frame_->IsFullscreen() ? 0 :
-        resize_inside_bounds_size;
-    int frame_component = GetHTComponentForFrame(point,
-                                                 resize_border,
-                                                 resize_border,
-                                                 resize_area_corner_size,
-                                                 resize_area_corner_size,
-                                                 can_ever_resize);
-    if (frame_component != HTNOWHERE)
-      return frame_component;
-  }
+  // Don't allow overlapping resize handles when the window is maximized or
+  // fullscreen, as it can't be resized in those states.
+  int resize_border =
+      (frame_->IsMaximized() || frame_->IsFullscreen()) ? 0 :
+      resize_inside_bounds_size;
+  int frame_component = GetHTComponentForFrame(point,
+                                               resize_border,
+                                               resize_border,
+                                               resize_area_corner_size,
+                                               resize_area_corner_size,
+                                               can_ever_resize);
+  if (frame_component != HTNOWHERE)
+    return frame_component;
 
   // Check for possible draggable region in the client area for the frameless
   // window.
diff --git a/chrome/browser/ui/views/external_tab_container_win.cc b/chrome/browser/ui/views/external_tab_container_win.cc
index 63e2688..b921b66 100644
--- a/chrome/browser/ui/views/external_tab_container_win.cc
+++ b/chrome/browser/ui/views/external_tab_container_win.cc
@@ -66,9 +66,7 @@
 #include "content/public/common/ssl_status.h"
 #include "grit/generated_resources.h"
 #include "grit/locale_settings.h"
-#include "third_party/WebKit/public/platform/WebCString.h"
 #include "third_party/WebKit/public/platform/WebReferrerPolicy.h"
-#include "third_party/WebKit/public/platform/WebString.h"
 #include "ui/base/events/event_utils.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/models/menu_model.h"
@@ -93,9 +91,7 @@
 using content::RenderViewHost;
 using content::SSLStatus;
 using content::WebContents;
-using WebKit::WebCString;
 using WebKit::WebReferrerPolicy;
-using WebKit::WebString;
 
 namespace {
 
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc
index 913a417..7e7add1 100644
--- a/chrome/browser/ui/views/frame/browser_view.cc
+++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -35,6 +35,8 @@
 #include "chrome/browser/themes/theme_service_factory.h"
 #include "chrome/browser/ui/app_modal_dialogs/app_modal_dialog.h"
 #include "chrome/browser/ui/app_modal_dialogs/app_modal_dialog_queue.h"
+#include "chrome/browser/ui/bookmarks/bookmark_bubble_delegate.h"
+#include "chrome/browser/ui/bookmarks/bookmark_bubble_sign_in_delegate.h"
 #include "chrome/browser/ui/bookmarks/bookmark_utils.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_command_controller.h"
@@ -66,8 +68,6 @@
 #include "chrome/browser/ui/views/frame/browser_view_layout_delegate.h"
 #include "chrome/browser/ui/views/frame/contents_container.h"
 #include "chrome/browser/ui/views/frame/immersive_mode_controller.h"
-#include "chrome/browser/ui/views/frame/instant_overlay_controller_views.h"
-#include "chrome/browser/ui/views/frame/overlay_container.h"
 #include "chrome/browser/ui/views/frame/top_container_view.h"
 #include "chrome/browser/ui/views/fullscreen_exit_bubble_views.h"
 #include "chrome/browser/ui/views/infobars/infobar_container_view.h"
@@ -399,7 +399,6 @@
       contents_web_view_(NULL),
       devtools_container_(NULL),
       contents_container_(NULL),
-      overlay_container_(NULL),
       contents_split_(NULL),
       devtools_dock_side_(DEVTOOLS_DOCK_SIDE_BOTTOM),
       devtools_window_(NULL),
@@ -425,8 +424,6 @@
   // Immersive mode may need to reparent views before they are removed/deleted.
   immersive_mode_controller_.reset();
 
-  overlay_controller_.reset();
-
   browser_->tab_strip_model()->RemoveObserver(this);
 
 #if defined(OS_WIN) && !defined(USE_AURA)
@@ -930,29 +927,6 @@
   }
 }
 
-void BrowserView::OnOverlayStateChanged(bool repaint_infobars) {
-  Layout();
-
-  // |top_container_| paints to a layer when in immersive fullscreen. Paint
-  // |overlay_container_| to a layer in this case so that the overlay stays
-  // stacked on top of |top_container_| in z-order.
-  if (overlay_container_->visible() &&
-      immersive_mode_controller_->IsRevealed()) {
-    overlay_container_->SetPaintToLayer(true);
-    overlay_container_->SetFillsBoundsOpaquely(false);
-  }
-
-  // When immersive mode is not reveal and infobar container is visible, set top
-  // infobar arrow as per overlay state.  Layout() needs to happen before
-  // GetMaxTopInfoBarArrowHeight() because the latter checks for visibility of
-  // overlay_container_| which is determined in Layout().
-  if (repaint_infobars &&
-      infobar_container_->visible() &&
-      !immersive_mode_controller_->IsRevealed()) {
-    infobar_container_->SetMaxTopArrowHeight(GetMaxTopInfoBarArrowHeight());
-  }
-}
-
 LocationBar* BrowserView::GetLocationBar() const {
   return GetLocationBarView();
 }
@@ -1115,9 +1089,15 @@
 }
 
 void BrowserView::ShowBookmarkBubble(const GURL& url, bool already_bookmarked) {
+  scoped_ptr<BookmarkBubbleDelegate> delegate;
+  delegate.reset(new BookmarkBubbleSignInDelegate(browser_.get()));
+
   chrome::ShowBookmarkBubbleView(GetToolbarView()->GetBookmarkBubbleAnchor(),
-                                 bookmark_bar_view_.get(), browser_->profile(),
-                                 url, !already_bookmarked);
+                                 bookmark_bar_view_.get(),
+                                 delegate.Pass(),
+                                 browser_->profile(),
+                                 url,
+                                 !already_bookmarked);
 }
 
 void BrowserView::ShowBookmarkPrompt() {
@@ -1190,8 +1170,6 @@
 void BrowserView::WebContentsFocused(WebContents* contents) {
   if (contents_web_view_->GetWebContents() == contents)
     contents_web_view_->OnWebContentsFocused(contents);
-  else if (overlay_container_->overlay_web_contents() == contents)
-    overlay_controller_->overlay()->OnWebContentsFocused(contents);
   else
     devtools_container_->OnWebContentsFocused(contents);
 }
@@ -1405,15 +1383,6 @@
                                    int reason) {
   DCHECK(new_contents);
 
-  // See if the Instant overlay is being activated (committed).
-  if (overlay_container_->overlay_web_contents() == new_contents) {
-    MakeOverlayContentsActiveContents();
-    views::WebView* old_container = contents_web_view_;
-    contents_web_view_ = overlay_controller_->release_overlay();
-    old_container->SetWebContents(NULL);
-    delete old_container;
-  }
-
   // If |contents_container_| already has the correct WebContents, we can save
   // some work.  This also prevents extra events from being reported by the
   // Visibility API under Windows, as ChangeWebContents will briefly hide
@@ -1906,6 +1875,10 @@
     tabstrip_->SetImmersiveStyle(immersive);
 }
 
+WebContents* BrowserView::GetWebContents() {
+  return GetActiveWebContents();
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 // BrowserView, InfoBarContainer::Delegate overrides:
 
@@ -2018,17 +1991,9 @@
   find_bar_host_view_ = new View();
   AddChildView(find_bar_host_view_);
 
-  overlay_container_ =
-      new OverlayContainer(this, immersive_mode_controller_.get());
-  overlay_container_->SetVisible(false);
-  AddChildView(overlay_container_);
-
   if (window_switcher_button_)
     AddChildView(window_switcher_button_);
 
-  overlay_controller_.reset(
-      new InstantOverlayControllerViews(browser(), overlay_container_));
-
   immersive_mode_controller_->Init(this, GetWidget(), top_container_);
 
   BrowserViewLayout* browser_view_layout = new BrowserViewLayout;
@@ -2041,7 +2006,6 @@
                             infobar_container_,
                             contents_split_,
                             contents_container_,
-                            overlay_container_,
                             immersive_mode_controller_.get());
   SetLayoutManager(browser_view_layout);
 
@@ -2694,39 +2658,11 @@
   AppModalDialogQueue::GetInstance()->ActivateModalDialog();
 }
 
-void BrowserView::MakeOverlayContentsActiveContents() {
-  views::WebView* overlay = overlay_controller_->overlay();
-  DCHECK_EQ(overlay_container_, overlay->parent());
-  overlay_container_->ResetOverlayAndContents();
-
-  // |overlay|'s current parent is |OverlayContainer|, and will be reparented
-  // to |ContentsContainer|.  |overlay|'s height is either same as
-  // |contents_web_view_| or taller when it appears over the attached bookmark
-  // and/or info bars.  The latter means it's also taller than the parent's
-  // height since |contents_web_view_|'s max height is the parent's height.
-  // Reparenting this taller overlay will force a clip to be installed on it;
-  // on ChromeOS, this results in a call into not-implemented
-  // views::NativeViewHostAura::InstallClip().  So set the bounds of |overlay|
-  // to same as |contents_web_view_| before reparenting.
-  // Note:
-  // - |overlay|'s origin is not (0,0), so just resizing it without changing the
-  //   origin may still result in the undesired clipping
-  // - there won't be extra repositioning or resizing of |overlay| since its new
-  //   bounds will be unchanged in ContentsContainer::Layout().
-  if (overlay->bounds().bottom() > contents_container_->height())
-    overlay->SetBoundsRect(contents_web_view_->bounds());
-  contents_container_->AddChildView(overlay);
-  contents_container_->SetActive(overlay);
-
-  // Overlay is gone, force re-layout of |BrowserView| and infobars.
-  OnOverlayStateChanged(true);
-}
-
 int BrowserView::GetMaxTopInfoBarArrowHeight() {
   int top_arrow_height = 0;
-  // Only show the arrows when not in fullscreen and when there's no overlay
-  // and no omnibox popup.
-  if (!IsFullscreen() && !overlay_container_->visible() &&
+  // Only show the arrows when not in fullscreen and when there's no omnibox
+  // popup.
+  if (!IsFullscreen() &&
       !GetLocationBar()->GetLocationEntry()->model()->popup_model()->IsOpen()) {
     const LocationIconView* location_icon_view =
         toolbar_->location_bar()->location_icon_view();
diff --git a/chrome/browser/ui/views/frame/browser_view.h b/chrome/browser/ui/views/frame/browser_view.h
index 2da4edc..6d0c871 100644
--- a/chrome/browser/ui/views/frame/browser_view.h
+++ b/chrome/browser/ui/views/frame/browser_view.h
@@ -48,9 +48,7 @@
 class DownloadShelfView;
 class FullscreenExitBubbleViews;
 class InfoBarContainerView;
-class InstantOverlayControllerViews;
 class LocationBarView;
-class OverlayContainer;
 class StatusBubbleViews;
 class SearchViewController;
 class TabStrip;
@@ -257,10 +255,6 @@
   // animations.
   void ToolbarSizeChanged(bool is_animating);
 
-  // Called from OverlayContainer::SetOverlay() when overlay is to be shown,
-  // expanded or hidden.  Set |repaint_infobars| to true to repaint infobars.
-  void OnOverlayStateChanged(bool repaint_infobars);
-
 #if defined(USE_ASH)
   // Test support.
   // Note: This is only needed to be BrowserLauncherItemController instead of
@@ -441,6 +435,7 @@
   virtual FullscreenController* GetFullscreenController() OVERRIDE;
   virtual void FullscreenStateChanged() OVERRIDE;
   virtual void SetImmersiveStyle(bool immersive) OVERRIDE;
+  virtual content::WebContents* GetWebContents() OVERRIDE;
 
   // InfoBarContainer::Delegate overrides
   virtual SkColor GetInfoBarSeparatorColor() const OVERRIDE;
@@ -473,9 +468,6 @@
   ContentsContainer* GetContentsContainerForTest() {
     return contents_container_;
   }
-  OverlayContainer* GetOverlayContainerForTest() {
-    return overlay_container_;
-  }
   views::WebView* GetContentsWebViewForTest() { return contents_web_view_; }
 
  private:
@@ -609,11 +601,6 @@
   // an existing showing one to the front.
   void ActivateAppModalDialog() const;
 
-  // Called when overlay is committed, i.e. made the active contents, where
-  // the overlay is reparented from |overlay_container_| to
-  // |contents_container_|.
-  void MakeOverlayContentsActiveContents();
-
   // Returns the max top arrow height for infobar.
   int GetMaxTopInfoBarArrowHeight();
 
@@ -636,16 +623,9 @@
   // |  | Navigation buttons, address bar, menu (toolbar_)           |  |
   // |  --------------------------------------------------------------  |
   // |------------------------------------------------------------------|
-  // | OverlayContainer (overlay_container_) [1]                        |
-  // |  --------------------------------------------------------------  |
-  // |  | overlay_controller_->overlay_                              |  |
-  // |  |------------------------------------------------------------|  |
-  // |  | overlay drop shadow if overlay is partial-height           |  |
-  // |  --------------------------------------------------------------  |
+  // | All infobars (infobar_container_) [1]                            |
   // |------------------------------------------------------------------|
-  // | All infobars (infobar_container_) [2]                            |
-  // |------------------------------------------------------------------|
-  // | Bookmarks (bookmark_bar_view_) [2]                               |
+  // | Bookmarks (bookmark_bar_view_) [1]                               |
   // |------------------------------------------------------------------|
   // | Debugger splitter (contents_split_)                              |
   // |  --------------------------------------------------------------  |
@@ -662,17 +642,14 @@
   // | Active downloads (download_shelf_)                               |
   // --------------------------------------------------------------------
   //
-  // [1] Overlay container is only visible when there's an overlay; it is
-  //     directly below the toolbar in the y-axis, and appears on top the
-  //     attached bookmark and/or info bars.
-  // [2] The bookmark bar and info bar are swapped when on the new tab page.
-  //     Additionally contents_container_ is positioned on top of the bookmark
-  //     bar when the bookmark bar is detached. This is done to allow the
-  //     overlay_controller_->overlay_ to appear over the bookmark bar.
+  // [1] The bookmark bar and info bar are swapped when on the new tab page.
+  //     Additionally when the bookmark bar is detached, contents_container_ is
+  //     positioned on top of the bar while the tab's contents are placed below
+  //     the bar.  This allows the find bar to always align with the top of
+  //     contents_container_ regardless if there's bookmark or info bars.
 
   // The view that manages the tab strip, toolbar, and sometimes the bookmark
-  // bar. Stacked second in the view hiearachy behind |overlay_container_|
-  // (refer to comments for |overlay_container_|) so it can be used to slide out
+  // bar. Stacked top in the view hiearachy so it can be used to slide out
   // the top views in immersive fullscreen.
   TopContainerView* top_container_;
 
@@ -711,11 +688,6 @@
   // The view managing the |contents_web_view_|.
   ContentsContainer* contents_container_;
 
-  // The view managing the |overlay_controller_->overlay_| and, if necessary,
-  // a drop shadow below the overlay in the y-axis.  Stacked at the top of the
-  // view hiearachy so it can appear over attached bookmark and/or info bars.
-  OverlayContainer* overlay_container_;
-
   // Split view containing the contents container and devtools container.
   views::SingleSplitView* contents_split_;
 
@@ -790,8 +762,6 @@
 
   gfx::ScopedSysColorChangeListener color_change_listener_;
 
-  scoped_ptr<InstantOverlayControllerViews> overlay_controller_;
-
   mutable base::WeakPtrFactory<BrowserView> activate_modal_dialog_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(BrowserView);
diff --git a/chrome/browser/ui/views/frame/browser_view_interactive_uitest.cc b/chrome/browser/ui/views/frame/browser_view_interactive_uitest.cc
index 4440fcf..e225c63 100644
--- a/chrome/browser/ui/views/frame/browser_view_interactive_uitest.cc
+++ b/chrome/browser/ui/views/frame/browser_view_interactive_uitest.cc
@@ -15,7 +15,6 @@
 #include "chrome/browser/ui/views/bookmarks/bookmark_bar_view.h"
 #include "chrome/browser/ui/views/frame/contents_container.h"
 #include "chrome/browser/ui/views/frame/immersive_mode_controller.h"
-#include "chrome/browser/ui/views/frame/overlay_container.h"
 #include "chrome/browser/ui/views/frame/top_container_view.h"
 #include "chrome/browser/ui/views/location_bar/location_bar_view.h"
 #include "chrome/browser/ui/views/tabs/tab.h"
@@ -69,221 +68,3 @@
   // Focus is released from the location bar.
   EXPECT_FALSE(location_bar_view->Contains(focus_manager->GetFocusedView()));
 }
-
-//////////////////////////////////////////////////////////////////////////////
-
-#if defined(HTML_INSTANT_EXTENDED_POPUP)
-class BrowserViewInstantExtendedTest : public InProcessBrowserTest,
-                                       public InstantTestBase {
- public:
-  BrowserViewInstantExtendedTest() {}
-  virtual ~BrowserViewInstantExtendedTest() {}
-
-  virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
-    chrome::EnableInstantExtendedAPIForTesting();
-    ASSERT_TRUE(https_test_server().Start());
-    GURL instant_url = https_test_server().GetURL(
-        "files/instant_extended.html?strk=1&");
-    InstantTestBase::Init(instant_url);
-  }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(BrowserViewInstantExtendedTest);
-};
-
-IN_PROC_BROWSER_TEST_F(BrowserViewInstantExtendedTest,
-                       InstantExtendedForOverlay) {
-  BookmarkBarView::DisableAnimationsForTesting(true);
-
-  BrowserView* browser_view = static_cast<BrowserView*>(browser()->window());
-  ContentsContainer* contents_container =
-      browser_view->GetContentsContainerForTest();
-  OverlayContainer* overlay_container =
-      browser_view->GetOverlayContainerForTest();
-
-  // Start up instant.
-  ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-
-  // Enable attached bookmark bar.
-  BookmarkBarView* bookmark_bar = browser_view->GetBookmarkBarView();
-  chrome::ExecuteCommand(browser(), IDC_SHOW_BOOKMARK_BAR);
-  EXPECT_TRUE(bookmark_bar->visible());
-  EXPECT_FALSE(bookmark_bar->IsDetached());
-
-  // Overlay container is invisible but at front of view hierarchy.
-  EXPECT_FALSE(overlay_container->visible());
-  EXPECT_EQ(browser_view->child_count() - 1,
-            browser_view->GetIndexOf(overlay_container));
-
-  ////////////////////////////////////////////////////////////////////////////
-  // Test suggestions on a normal web page, which are in an overlay.
-
-  // Focus omnibox, which constructs an overlay web contents.
-  FocusOmniboxAndWaitForInstantOverlayAndNTPSupport();
-  // Typing in the omnibox should show suggestions in an overlay view.
-  SetOmniboxTextAndWaitForOverlayToShow("santa");
-  EXPECT_TRUE(instant()->model()->mode().is_search_suggestions());
-
-  views::WebView* overlay = overlay_container->GetOverlayWebViewForTest();
-  content::WebContents* overlay_contents = overlay->web_contents();
-
-  // Overlay container is still at front, but is now visible and has an overlay.
-  EXPECT_EQ(browser_view->child_count() - 1,
-            browser_view->GetIndexOf(overlay_container));
-  EXPECT_TRUE(overlay_container->visible());
-  EXPECT_EQ(overlay_container, overlay->parent());
-
-  // Content area is still immediately below the visible attached bookmark bar.
-  EXPECT_TRUE(bookmark_bar->visible());
-  EXPECT_EQ(GetRectInWidget(bookmark_bar).bottom(),
-            GetRectInWidget(browser_view->GetContentsWebViewForTest()).y());
-
-  // Overlay web view (with suggestions) aligns with the bottom of the toolbar.
-  gfx::Rect overlay_rect_in_widget = GetRectInWidget(
-      overlay_container->GetOverlayWebViewForTest());
-  EXPECT_EQ(GetRectInWidget(browser_view->toolbar()).bottom(),
-                            overlay_rect_in_widget.y());
-
-  // Commit the search by pressing Enter.
-  browser_view->GetLocationBar()->AcceptInput();
-
-  // Overlay is reparented to and becomes active in ContentsContainer with the
-  // same web contents, which is the active contents in browser, while overlay
-  // container is childless and invisible.
-  EXPECT_EQ(contents_container, overlay->parent());
-  EXPECT_EQ(overlay, contents_container->GetActiveWebViewForTest());
-  EXPECT_EQ(overlay_contents, overlay->web_contents());
-  EXPECT_EQ(overlay_contents,
-            browser()->tab_strip_model()->GetActiveWebContents());
-  EXPECT_EQ(1, contents_container->child_count());
-  EXPECT_EQ(0, overlay_container->child_count());
-  EXPECT_FALSE(overlay_container->visible());
-
-  BookmarkBarView::DisableAnimationsForTesting(false);
-}
-
-//////////////////////////////////////////////////////////////////////////////
-
-// Immersive fullscreen is currently enabled only on Chrome OS.
-#if defined(OS_CHROMEOS)
-
-class BrowserViewImmersiveInstantExtendedTest : public InProcessBrowserTest,
-                                                public InstantTestBase {
- public:
-  BrowserViewImmersiveInstantExtendedTest() {}
-  virtual ~BrowserViewImmersiveInstantExtendedTest() {}
-
-  virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
-    ImmersiveFullscreenConfiguration::EnableImmersiveFullscreenForTest();
-    chrome::EnableInstantExtendedAPIForTesting();
-    ASSERT_TRUE(https_test_server().Start());
-    GURL instant_url = https_test_server().GetURL(
-        "files/instant_extended.html?strk=1&");
-    InstantTestBase::Init(instant_url);
-  }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(BrowserViewImmersiveInstantExtendedTest);
-};
-
-IN_PROC_BROWSER_TEST_F(BrowserViewImmersiveInstantExtendedTest,
-                       ImmersiveInstantExtended) {
-  ui::ScopedAnimationDurationScaleMode zero_duration_mode(
-      ui::ScopedAnimationDurationScaleMode::ZERO_DURATION);
-  BookmarkBarView::DisableAnimationsForTesting(true);
-
-  // Cache some pointers we'll need below.
-  BrowserView* browser_view = static_cast<BrowserView*>(browser()->window());
-  ToolbarView* toolbar = browser_view->toolbar();
-
-  // Start up both instant and immersive fullscreen.
-  ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-  ASSERT_TRUE(ImmersiveFullscreenConfiguration::UseImmersiveFullscreen());
-  chrome::ToggleFullscreenMode(browser());
-  ASSERT_TRUE(browser_view->IsFullscreen());
-  ASSERT_TRUE(browser_view->immersive_mode_controller()->IsEnabled());
-
-  ////////////////////////////////////////////////////////////////////////////
-  // Test suggestions on a normal web page, which are in an overlay.
-
-  // Focus omnibox, which constructs an overlay web contents.
-  FocusOmniboxAndWaitForInstantOverlayAndNTPSupport();
-  EXPECT_TRUE(instant()->model()->mode().is_default());
-  // The above testing code doesn't trigger the views location bar focus path,
-  // so force it to happen explicitly.
-  browser_view->SetFocusToLocationBar(false);
-  EXPECT_TRUE(browser_view->immersive_mode_controller()->IsRevealed());
-  // Content area is immediately below the tab indicators.
-  views::WebView* contents_web_view =
-      browser_view->GetContentsWebViewForTest();
-  EXPECT_EQ(GetRectInWidget(browser_view).y() + Tab::GetImmersiveHeight(),
-            GetRectInWidget(contents_web_view).y());
-
-  // Typing in the omnibox should show suggestions in an overlay view.
-  SetOmniboxTextAndWaitForOverlayToShow("santa");
-  EXPECT_TRUE(instant()->model()->mode().is_search_suggestions());
-  // Content area is still immediately below the tab indicators.
-  EXPECT_EQ(GetRectInWidget(browser_view).y() + Tab::GetImmersiveHeight(),
-            GetRectInWidget(contents_web_view).y());
-  // Overlay web view (with suggestions) aligns with the bottom of the omnibox.
-  OverlayContainer* overlay_container =
-      browser_view->GetOverlayContainerForTest();
-  gfx::Rect overlay_rect_in_widget = GetRectInWidget(
-      overlay_container->GetOverlayWebViewForTest());
-  EXPECT_EQ(GetRectInWidget(toolbar).bottom(), overlay_rect_in_widget.y());
-
-  // Overlay container layer is on top of top container layer, so that it
-  // paints over the bookmark bar and bottom of toolbar.
-  ui::Layer* top_container_layer = browser_view->top_container()->layer();
-  if (top_container_layer != NULL) {
-    ui::Layer* overlay_container_layer = overlay_container->layer();
-    EXPECT_TRUE(overlay_container_layer != NULL);
-    if (overlay_container_layer && overlay_container_layer->parent()) {
-      const std::vector<ui::Layer*>& children =
-          overlay_container_layer->parent()->children();
-      size_t top_index =
-          std::find(children.begin(), children.end(), top_container_layer) -
-              children.begin();
-      size_t overlay_index =
-          std::find(children.begin(), children.end(), overlay_container_layer) -
-              children.begin();
-      EXPECT_TRUE(overlay_index > top_index);
-    }
-  }
-
-  ////////////////////////////////////////////////////////////////////////////
-  // Test suggestions on the NTP, which are not in an overlay.
-
-  // Navigate to the Instant NTP, and wait for it to be recognized.
-  content::WindowedNotificationObserver instant_tab_observer(
-      chrome::NOTIFICATION_INSTANT_TAB_SUPPORT_DETERMINED,
-      content::NotificationService::AllSources());
-  ui_test_utils::NavigateToURLWithDisposition(browser(),
-                                              GURL(chrome::kChromeUINewTabURL),
-                                              CURRENT_TAB,
-                                              ui_test_utils::BROWSER_TEST_NONE);
-  instant_tab_observer.Wait();
-
-  // Type in the omnibox, which should generate suggestions in the main page
-  // contents.
-  SetOmniboxText("claus");
-  while (!omnibox()->model()->autocomplete_controller()->done()) {
-    content::WindowedNotificationObserver autocomplete_observer(
-        chrome::NOTIFICATION_AUTOCOMPLETE_CONTROLLER_RESULT_READY,
-        content::NotificationService::AllSources());
-    autocomplete_observer.Wait();
-  }
-  // Ensure JavaScript has finished running by executing a blank script.
-  EXPECT_TRUE(ExecuteScript(std::string()));
-  // We're still revealed, since focus is in the omnibox.
-  EXPECT_TRUE(browser_view->immersive_mode_controller()->IsRevealed());
-  // The active web contents are aligned with the toolbar.
-  gfx::Rect web_view_rect_in_widget = GetRectInWidget(
-      browser_view->GetContentsContainerForTest()->GetActiveWebViewForTest());
-  EXPECT_EQ(GetRectInWidget(toolbar).bottom(), web_view_rect_in_widget.y());
-
-  BookmarkBarView::DisableAnimationsForTesting(false);
-}
-
-#endif  // defined(OS_CHROMEOS)
-#endif  // defined(HTML_INSTANT_EXTENDED_POPUP)
diff --git a/chrome/browser/ui/views/frame/browser_view_layout.cc b/chrome/browser/ui/views/frame/browser_view_layout.cc
index a015739..0a936d2 100644
--- a/chrome/browser/ui/views/frame/browser_view_layout.cc
+++ b/chrome/browser/ui/views/frame/browser_view_layout.cc
@@ -19,7 +19,6 @@
 #include "chrome/browser/ui/views/frame/browser_view_layout_delegate.h"
 #include "chrome/browser/ui/views/frame/contents_container.h"
 #include "chrome/browser/ui/views/frame/immersive_mode_controller.h"
-#include "chrome/browser/ui/views/frame/overlay_container.h"
 #include "chrome/browser/ui/views/frame/top_container_view.h"
 #include "chrome/browser/ui/views/fullscreen_exit_bubble_views.h"
 #include "chrome/browser/ui/views/infobars/infobar_container_view.h"
@@ -127,7 +126,6 @@
       infobar_container_(NULL),
       contents_split_(NULL),
       contents_container_(NULL),
-      overlay_container_(NULL),
       download_shelf_(NULL),
       immersive_mode_controller_(NULL),
       dialog_host_(new WebContentsModalDialogHostViews(this)),
@@ -146,7 +144,6 @@
     InfoBarContainerView* infobar_container,
     views::View* contents_split,
     ContentsContainer* contents_container,
-    OverlayContainer* overlay_container,
     ImmersiveModeController* immersive_mode_controller) {
   delegate_.reset(delegate);
   browser_ = browser;
@@ -157,7 +154,6 @@
   infobar_container_ = infobar_container;
   contents_split_ = contents_split;
   contents_container_ = contents_container;
-  overlay_container_ = overlay_container;
   immersive_mode_controller_ = immersive_mode_controller;
 }
 
@@ -339,15 +335,6 @@
   }
   top = LayoutToolbar(top);
 
-  // Overlay container requires updated toolbar bounds to determine its
-  // position, and needs to be laid out before:
-  // - GetTopMarginForActiveContent(), which calls GetInstantUIState() to check
-  //   if overlay container is visible
-  // - LayoutInfoBar(): children of infobar container will layout and call
-  //   BrowserView::DrawInfoBarArrows(), which checks if overlay container is
-  //   visible.
-  LayoutOverlayContainer();
-
   top = LayoutBookmarkAndInfoBars(top, browser_view->y());
 
   // Top container requires updated toolbar and bookmark bar to compute bounds.
@@ -356,16 +343,11 @@
   int bottom = LayoutDownloadShelf(browser_view->height());
   // Treat a detached bookmark bar as if the web contents container is shifted
   // upwards and overlaps it.
-  top -= GetContentsOffsetForBookmarkBar();
+  int active_top_margin = GetContentsOffsetForBookmarkBar();
+  contents_container_->SetActiveTopMargin(active_top_margin);
+  top -= active_top_margin;
   LayoutContentsSplitView(top, bottom);
 
-  // Instant extended can put suggestions in a web view, which can require an
-  // offset to align with the omnibox. This offset must be recomputed after
-  // split view layout to account for infobar heights.
-  int active_top_margin = GetTopMarginForActiveContent();
-  if (contents_container_->SetActiveTopMargin(active_top_margin))
-    contents_container_->Layout();
-
   // This must be done _after_ we lay out the WebContents since this
   // code calls back into us to find the bounding box the find bar
   // must be laid out within, and that code depends on the
@@ -532,29 +514,6 @@
   contents_split_->SetBoundsRect(contents_split_bounds);
 }
 
-void BrowserViewLayout::LayoutOverlayContainer() {
-  bool full_height = overlay_container_->IsOverlayFullHeight();
-  int preferred_height = 0;
-  if (!full_height)
-    preferred_height = overlay_container_->GetPreferredSize().height();
-  overlay_container_->SetVisible(full_height || preferred_height > 0);
-  if (!overlay_container_->visible())
-    return;
-  gfx::Point bottom_edge(0, toolbar_->bounds().bottom());
-  views::View::ConvertPointToTarget(
-      toolbar_->parent(), browser_view_, &bottom_edge);
-  // Overlaps with the toolbar like the attached bookmark bar would, so as to
-  // completely obscure the attached bookmark bar if it were visible.
-  bottom_edge.Offset(0,
-                     -(views::NonClientFrameView::kClientEdgeThickness +
-                       BookmarkBarView::kToolbarAttachedBookmarkBarOverlap));
-  gfx::Rect rect(vertical_layout_rect_);
-  rect.Inset(0, bottom_edge.y(), 0, 0);
-  if (!full_height && preferred_height < rect.height())
-    rect.set_height(preferred_height);
-  overlay_container_->SetBoundsRect(rect);
-}
-
 void BrowserViewLayout::UpdateTopContainerBounds() {
   gfx::Rect top_container_bounds(top_container_->GetPreferredSize());
 
@@ -584,48 +543,6 @@
       bookmark_bar_->GetFullyDetachedToolbarOverlap();
 }
 
-int BrowserViewLayout::GetTopMarginForActiveContent() {
-  // During an immersive reveal, if instant extended is showing suggestions
-  // in the main active web view, ensure that active web view appears aligned
-  // with the bottom of the omnibox.
-  InstantUIState instant_ui_state = GetInstantUIState();
-  if (instant_ui_state == kInstantUIFullPageResults &&
-      immersive_mode_controller_->IsRevealed())
-    return GetTopMarginForImmersiveInstant();
-
-  // Usually we only use a margin if there's a detached bookmarks bar.
-  return GetContentsOffsetForBookmarkBar();
-}
-
-int BrowserViewLayout::GetTopMarginForImmersiveInstant() {
-  // Compute the position of the bottom edge of the top container views,
-  // expressed as an offset in the coordinates of |contents_container_|,
-  // because the offset will be applied in |contents_container_| layout.
-  // NOTE: This requires contents_split_ layout to be complete, as the
-  // coordinate system conversion depends on the contents_split_ origin.
-  gfx::Point bottom_edge(0, top_container_->height());
-  views::View::ConvertPointToTarget(top_container_,
-                                    contents_container_,
-                                    &bottom_edge);
-  return bottom_edge.y();
-}
-
-BrowserViewLayout::InstantUIState BrowserViewLayout::GetInstantUIState() {
-  if (!browser()->search_model()->mode().is_search())
-    return kInstantUINone;
-
-  // If the search suggestions are already being displayed in the overlay
-  // contents then return kInstantUIOverlay.
-  if (overlay_container_->visible())
-    return kInstantUIOverlay;
-
-  // Top bars stay visible until the results page notifies Chrome it is ready.
-  if (browser()->search_model()->top_bars_visible())
-    return kInstantUINone;
-
-  return kInstantUIFullPageResults;
-}
-
 int BrowserViewLayout::LayoutDownloadShelf(int bottom) {
   if (delegate_->DownloadShelfNeedsLayout()) {
     bool visible = browser()->SupportsWindowFeature(
diff --git a/chrome/browser/ui/views/frame/browser_view_layout.h b/chrome/browser/ui/views/frame/browser_view_layout.h
index c0e8287..dd64a40 100644
--- a/chrome/browser/ui/views/frame/browser_view_layout.h
+++ b/chrome/browser/ui/views/frame/browser_view_layout.h
@@ -19,7 +19,6 @@
 class ContentsContainer;
 class ImmersiveModeController;
 class InfoBarContainerView;
-class OverlayContainer;
 class TabContentsContainer;
 class TabStrip;
 
@@ -56,7 +55,6 @@
             InfoBarContainerView* infobar_container,
             views::View* contents_split,
             ContentsContainer* contents_container,
-            OverlayContainer* overlay_container,
             ImmersiveModeController* immersive_mode_controller);
 
   // Sets or updates views that are not available when |this| is initialized.
@@ -98,16 +96,6 @@
   FRIEND_TEST_ALL_PREFIXES(BrowserViewLayoutTest, LayoutDownloadShelf);
   class WebContentsModalDialogHostViews;
 
-  enum InstantUIState {
-    // No instant suggestions are being shown.
-    kInstantUINone,
-    // Instant suggestions are displayed in a overlay overlapping the tab
-    // contents.
-    kInstantUIOverlay,
-    // Instant suggestions are displayed in the main tab contents.
-    kInstantUIFullPageResults,
-  };
-
   Browser* browser() { return browser_; }
 
   // Layout the tab strip region, returns the coordinate of the bottom of the
@@ -126,9 +114,6 @@
   // |contents_split_| and other views.
   void LayoutContentsSplitView(int top, int bottom);
 
-  // Layout the |overlay_container_| view below the toolbar.
-  void LayoutOverlayContainer();
-
   // Updates |top_container_|'s bounds. The new bounds depend on the size of
   // the bookmark bar and the toolbar.
   void UpdateTopContainerBounds();
@@ -142,14 +127,6 @@
   // preview contents hides the bookmark bar.
   int GetTopMarginForActiveContent();
 
-  // Returns the top margin for the active or overlay web view in
-  // |contents_container_| for an immersive fullscreen reveal while instant
-  // extended is providing suggestions.
-  int GetTopMarginForImmersiveInstant();
-
-  // Returns the state of instant extended suggestions.
-  InstantUIState GetInstantUIState();
-
   // Layout the Download Shelf, returns the coordinate of the top of the
   // control, for laying out the previous control.
   int LayoutDownloadShelf(int bottom);
@@ -177,7 +154,6 @@
   InfoBarContainerView* infobar_container_;
   views::View* contents_split_;
   ContentsContainer* contents_container_;
-  OverlayContainer* overlay_container_;
   views::View* download_shelf_;
 
   ImmersiveModeController* immersive_mode_controller_;
diff --git a/chrome/browser/ui/views/frame/browser_view_layout_unittest.cc b/chrome/browser/ui/views/frame/browser_view_layout_unittest.cc
index 104c403..09226ba 100644
--- a/chrome/browser/ui/views/frame/browser_view_layout_unittest.cc
+++ b/chrome/browser/ui/views/frame/browser_view_layout_unittest.cc
@@ -8,7 +8,6 @@
 #include "chrome/browser/ui/views/frame/browser_view_layout_delegate.h"
 #include "chrome/browser/ui/views/frame/contents_container.h"
 #include "chrome/browser/ui/views/frame/immersive_mode_controller.h"
-#include "chrome/browser/ui/views/frame/overlay_container.h"
 #include "chrome/browser/ui/views/infobars/infobar_container_view.h"
 #include "chrome/browser/ui/views/tabs/tab_strip.h"
 #include "chrome/test/base/browser_with_test_window_test.h"
@@ -134,7 +133,6 @@
         infobar_container_(NULL),
         contents_split_(NULL),
         contents_container_(NULL),
-        overlay_container_(NULL),
         active_web_view_(NULL) {}
   virtual ~BrowserViewLayoutTest() {}
 
@@ -163,10 +161,6 @@
     top_container_->AddChildView(toolbar_);
     root_view_->AddChildView(top_container_);
 
-    overlay_container_ =
-        new OverlayContainer(NULL, immersive_mode_controller_.get());
-    root_view_->AddChildView(overlay_container_);
-
     infobar_container_ = new InfoBarContainerView(NULL);
     root_view_->AddChildView(infobar_container_);
 
@@ -188,7 +182,6 @@
                   infobar_container_,
                   contents_split_,
                   contents_container_,
-                  overlay_container_,
                   immersive_mode_controller_.get());
   }
 
@@ -204,7 +197,6 @@
   InfoBarContainerView* infobar_container_;
   MockView* contents_split_;
   ContentsContainer* contents_container_;
-  OverlayContainer* overlay_container_;
   MockView* active_web_view_;
 
   scoped_ptr<MockImmersiveModeController> immersive_mode_controller_;
@@ -216,7 +208,6 @@
 TEST_F(BrowserViewLayoutTest, BrowserViewLayout) {
   EXPECT_TRUE(layout()->browser());
   EXPECT_TRUE(layout()->GetWebContentsModalDialogHost());
-  EXPECT_EQ(BrowserViewLayout::kInstantUINone, layout()->GetInstantUIState());
   EXPECT_FALSE(layout()->InfobarVisible());
 }
 
diff --git a/chrome/browser/ui/views/frame/browser_view_unittest.cc b/chrome/browser/ui/views/frame/browser_view_unittest.cc
index c140e6b..8bb3377 100644
--- a/chrome/browser/ui/views/frame/browser_view_unittest.cc
+++ b/chrome/browser/ui/views/frame/browser_view_unittest.cc
@@ -15,7 +15,6 @@
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/views/bookmarks/bookmark_bar_view.h"
 #include "chrome/browser/ui/views/frame/browser_view_layout.h"
-#include "chrome/browser/ui/views/frame/overlay_container.h"
 #include "chrome/browser/ui/views/frame/top_container_view.h"
 #include "chrome/browser/ui/views/infobars/infobar_container_view.h"
 #include "chrome/browser/ui/views/tabs/tab_strip.h"
@@ -172,8 +171,6 @@
       browser_view()->GetContentsSplitForTest();
   views::WebView* contents_web_view =
       browser_view()->GetContentsWebViewForTest();
-  OverlayContainer* overlay_container =
-      browser_view()->GetOverlayContainerForTest();
 
   // Start with a single tab open to a normal page.
   AddTab(browser, GURL("about:blank"));
@@ -183,15 +180,12 @@
   EXPECT_EQ(top_container, browser_view()->toolbar()->parent());
   EXPECT_EQ(top_container, browser_view()->GetBookmarkBarView()->parent());
   EXPECT_EQ(browser_view(), browser_view()->infobar_container()->parent());
-  EXPECT_EQ(browser_view(), overlay_container->parent());
 
-  // Overlay container is at the front of the view hierarchy, followed by the
-  // find bar host and the top container.
+  // Find bar host is at the front of the view hierarchy, followed by the top
+  // container.
   EXPECT_EQ(browser_view()->child_count() - 1,
-            browser_view()->GetIndexOf(overlay_container));
-  EXPECT_EQ(browser_view()->child_count() - 2,
             browser_view()->GetIndexOf(browser_view()->find_bar_host_view()));
-  EXPECT_EQ(browser_view()->child_count() - 3,
+  EXPECT_EQ(browser_view()->child_count() - 2,
             browser_view()->GetIndexOf(top_container));
 
   // Verify basic layout.
@@ -230,13 +224,11 @@
   EXPECT_TRUE(bookmark_bar->visible());
   EXPECT_TRUE(bookmark_bar->IsDetached());
   EXPECT_EQ(browser_view(), bookmark_bar->parent());
-  // Overlay container is still at the front of the view hierarchy, followed by
-  // the find bar host and the top container.
+  // Find bar host is still at the front of the view hierarchy, followed by
+  // the top container.
   EXPECT_EQ(browser_view()->child_count() - 1,
-            browser_view()->GetIndexOf(overlay_container));
-  EXPECT_EQ(browser_view()->child_count() - 2,
             browser_view()->GetIndexOf(browser_view()->find_bar_host_view()));
-  EXPECT_EQ(browser_view()->child_count() - 3,
+  EXPECT_EQ(browser_view()->child_count() - 2,
             browser_view()->GetIndexOf(top_container));
 
   // Bookmark bar layout on NTP.
@@ -260,8 +252,8 @@
   EXPECT_FALSE(bookmark_bar->visible());
   EXPECT_FALSE(bookmark_bar->IsDetached());
   EXPECT_EQ(top_container, bookmark_bar->parent());
-  // Top container is still third from front.
-  EXPECT_EQ(browser_view()->child_count() - 3,
+  // Top container is still second from front.
+  EXPECT_EQ(browser_view()->child_count() - 2,
             browser_view()->GetIndexOf(top_container));
 
   BookmarkBarView::DisableAnimationsForTesting(false);
diff --git a/chrome/browser/ui/views/frame/immersive_mode_controller.h b/chrome/browser/ui/views/frame/immersive_mode_controller.h
index f8f23de..f4a504b 100644
--- a/chrome/browser/ui/views/frame/immersive_mode_controller.h
+++ b/chrome/browser/ui/views/frame/immersive_mode_controller.h
@@ -11,6 +11,10 @@
 class BookmarkBarView;
 class FullscreenController;
 
+namespace content {
+class WebContents;
+}
+
 namespace gfx {
 class Rect;
 class Size;
@@ -61,6 +65,10 @@
     // Returns the browser's FullscreenController.
     virtual FullscreenController* GetFullscreenController() = 0;
 
+    // Returns the browser's active web contents for the active tab, or NULL if
+    // such does not exist.
+    virtual content::WebContents* GetWebContents() = 0;
+
     // Notifies the delegate that fullscreen has been entered or exited.
     virtual void FullscreenStateChanged() = 0;
 
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 8b1b5f7..9fd4fac 100644
--- a/chrome/browser/ui/views/frame/immersive_mode_controller_ash.cc
+++ b/chrome/browser/ui/views/frame/immersive_mode_controller_ash.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/ui/views/frame/immersive_mode_controller_ash.h"
 
 #include <set>
+#include <vector>
 
 #include "ash/ash_switches.h"
 #include "ash/shell.h"
@@ -16,6 +17,8 @@
 #include "chrome/browser/ui/views/bookmarks/bookmark_bar_view.h"
 #include "chrome/browser/ui/views/frame/top_container_view.h"
 #include "content/public/browser/notification_service.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_view.h"
 #include "ui/aura/client/activation_client.h"
 #include "ui/aura/client/aura_constants.h"
 #include "ui/aura/client/capture_client.h"
@@ -48,7 +51,7 @@
 // How many pixels a gesture can start away from |top_container_| when in
 // closed state and still be considered near it. This is needed to overcome
 // issues with poor location values near the edge of the display.
-const int kNearTopContainerDistance = 5;
+const int kNearTopContainerDistance = 8;
 
 // Used to multiply x value of an update in check to determine if gesture is
 // vertical. This is used to make sure that gesture is close to vertical instead
@@ -347,6 +350,7 @@
     reveal_state_ = CLOSED;
     EnablePaintToLayer(false);
     delegate_->SetImmersiveStyle(false);
+    SetRenderWindowTopInsetsForTouch(0);
 
     // Relayout the root view because disabling immersive fullscreen may have
     // changed the result of NonClientFrameView::GetBoundsForClientView().
@@ -940,6 +944,7 @@
     // top-of-window views to their initial offscreen position for the
     // animation.
     delegate_->SetImmersiveStyle(false);
+    SetRenderWindowTopInsetsForTouch(0);
     LayoutBrowserRootView();
 
     // Do not do any more processing if LayoutBrowserView() changed
@@ -959,7 +964,7 @@
     animation_->Show();
   }
 
-   if (previous_reveal_state == CLOSED)
+  if (previous_reveal_state == CLOSED)
      FOR_EACH_OBSERVER(Observer, observers_, OnImmersiveRevealStarted());
 }
 
@@ -1037,6 +1042,7 @@
   EnablePaintToLayer(false);
   // Update tabstrip for closed state.
   delegate_->SetImmersiveStyle(true);
+  SetRenderWindowTopInsetsForTouch(kNearTopContainerDistance);
   LayoutBrowserRootView();
 }
 
@@ -1083,6 +1089,18 @@
        (location.x() < near_bounds.right()));
 }
 
+void ImmersiveModeControllerAsh::SetRenderWindowTopInsetsForTouch(
+    int top_inset) {
+  content::WebContents* contents = delegate_->GetWebContents();
+  if (contents) {
+    aura::Window* window = contents->GetView()->GetContentNativeView();
+    gfx::Insets inset(top_inset, 0, 0, 0);
+    window->SetHitTestBoundsOverrideOuter(
+        window->hit_test_bounds_override_outer_mouse(),
+        inset);
+  }
+}
+
 void ImmersiveModeControllerAsh::RecreateBubbleManager() {
   bubble_manager_.reset(new BubbleManager(this));
   const std::vector<aura::Window*> transient_children =
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 a1e909e..8ba1f2a 100644
--- a/chrome/browser/ui/views/frame/immersive_mode_controller_ash.h
+++ b/chrome/browser/ui/views/frame/immersive_mode_controller_ash.h
@@ -223,6 +223,13 @@
   // child of |top_container_|.
   void RecreateBubbleManager();
 
+  // Shrinks or expands the touch hit test by updating insets for the render
+  // window depending on if top_inset is positive or negative respectively.
+  // Used to ensure that touch events at the top of the screen go to the top
+  // container so a slide gesture can be generated when the content window is
+  // consuming all touch events sent to it.
+  void SetRenderWindowTopInsetsForTouch(int top_inset);
+
   // Injected dependencies. Not owned.
   Delegate* delegate_;
   views::Widget* widget_;
diff --git a/chrome/browser/ui/views/frame/immersive_mode_controller_ash_browsertest.cc b/chrome/browser/ui/views/frame/immersive_mode_controller_ash_browsertest.cc
index 644798b..450115c 100644
--- a/chrome/browser/ui/views/frame/immersive_mode_controller_ash_browsertest.cc
+++ b/chrome/browser/ui/views/frame/immersive_mode_controller_ash_browsertest.cc
@@ -23,6 +23,8 @@
 #include "chrome/browser/ui/views/tabs/tab_strip.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 "content/public/browser/web_contents_view.h"
 #include "content/public/test/test_utils.h"
 #include "ui/aura/client/screen_position_client.h"
 #include "ui/aura/env.h"
@@ -422,4 +424,36 @@
   EXPECT_TRUE(controller()->ShouldHideTabIndicators());
 }
 
+// Validate top container touch insets are being updated at the correct time in
+// immersive mode.
+IN_PROC_BROWSER_TEST_F(ImmersiveModeControllerAshTest,
+                       ImmersiveTopContainerInsets) {
+  content::WebContents* contents = browser_view()->GetActiveWebContents();
+  aura::Window* window = contents->GetView()->GetContentNativeView();
+
+  // Turning immersive mode on sets positive top touch insets on the render view
+  // window.
+  chrome::ToggleFullscreenMode(browser());
+  ASSERT_TRUE(browser_view()->IsFullscreen());
+  ASSERT_TRUE(controller()->IsEnabled());
+  EXPECT_TRUE(window->hit_test_bounds_override_outer_touch().top() > 0);
+
+  // Trigger a reveal resets insets as now the touch target for the top
+  // container is large enough.
+  controller()->StartRevealForTest(true);
+  EXPECT_TRUE(window->hit_test_bounds_override_outer_touch().top() == 0);
+
+  // End reveal by moving the mouse off the top-of-window views. We
+  // should see the top insets being positive again to allow a bigger touch
+  // target.
+  controller()->SetMouseHoveredForTest(false);
+  EXPECT_TRUE(window->hit_test_bounds_override_outer_touch().top() > 0);
+
+  // Disabling immersive mode resets the top touch insets to 0.
+  chrome::ToggleFullscreenMode(browser());
+  ASSERT_FALSE(browser_view()->IsFullscreen());
+  ASSERT_FALSE(controller()->IsEnabled());
+  EXPECT_TRUE(window->hit_test_bounds_override_outer_touch().top() == 0);
+}
+
 #endif  // defined(OS_CHROMEOS)
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 b02982b..3a206ab 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
@@ -34,6 +34,9 @@
   virtual void SetImmersiveStyle(bool immersive) OVERRIDE {
     immersive_style_ = immersive;
   }
+  virtual content::WebContents* GetWebContents() OVERRIDE {
+    return NULL;
+  }
 
  private:
   bool immersive_style_;
diff --git a/chrome/browser/ui/views/frame/instant_overlay_controller_views.cc b/chrome/browser/ui/views/frame/instant_overlay_controller_views.cc
deleted file mode 100644
index abee4db..0000000
--- a/chrome/browser/ui/views/frame/instant_overlay_controller_views.cc
+++ /dev/null
@@ -1,56 +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/ui/views/frame/instant_overlay_controller_views.h"
-
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/search/search.h"
-#include "chrome/browser/ui/browser.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"
-#include "chrome/browser/ui/view_ids.h"
-#include "chrome/browser/ui/views/frame/overlay_container.h"
-#include "chrome/browser/ui/views/infobars/infobar_container_view.h"
-#include "ui/views/controls/webview/webview.h"
-
-InstantOverlayControllerViews::InstantOverlayControllerViews(
-    Browser* browser,
-    OverlayContainer* overlay_container)
-    : InstantOverlayController(browser),
-      overlay_container_(overlay_container) {
-}
-
-InstantOverlayControllerViews::~InstantOverlayControllerViews() {
-}
-
-void InstantOverlayControllerViews::OverlayStateChanged(
-    const InstantOverlayModel& model) {
-  if (model.mode().is_ntp() || model.mode().is_search_suggestions()) {
-    // Show the overlay.
-    if (!overlay_) {
-      overlay_.reset(new views::WebView(browser_->profile()));
-      overlay_->set_id(VIEW_ID_TAB_CONTAINER);
-    }
-    // Drop shadow is only needed if search mode is not |NTP| and overlay does
-    // not fill up the entire contents page.
-    bool draw_drop_shadow = !model.mode().is_ntp() &&
-        !(overlay_container_->WillOverlayBeFullHeight(model.height(),
-                                                      model.height_units()));
-    content::WebContents* web_contents = model.GetOverlayContents();
-    overlay_container_->SetOverlay(overlay_.get(),
-                                   web_contents,
-                                   model.height(),
-                                   model.height_units(),
-                                   draw_drop_shadow);
-    overlay_->SetWebContents(web_contents);
-  } else if (overlay_) {
-    // Hide the overlay. SetWebContents() must happen before SetOverlay().
-    overlay_->SetWebContents(NULL);
-    overlay_container_->SetOverlay(
-        NULL, NULL, 100, INSTANT_SIZE_PERCENT, false);
-    overlay_.reset();
-  }
-}
diff --git a/chrome/browser/ui/views/frame/instant_overlay_controller_views.h b/chrome/browser/ui/views/frame/instant_overlay_controller_views.h
deleted file mode 100644
index 59fa5a3..0000000
--- a/chrome/browser/ui/views/frame/instant_overlay_controller_views.h
+++ /dev/null
@@ -1,47 +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_VIEWS_FRAME_INSTANT_OVERLAY_CONTROLLER_VIEWS_H_
-#define CHROME_BROWSER_UI_VIEWS_FRAME_INSTANT_OVERLAY_CONTROLLER_VIEWS_H_
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "base/memory/scoped_ptr.h"
-#include "chrome/browser/ui/search/instant_overlay_controller.h"
-
-class Browser;
-class OverlayContainer;
-
-namespace views {
-class WebView;
-}
-
-// A controller that manages the Views-specific Instant overlay. Its primary
-// role is to respond to display-state changes from the Instant model and
-// reflect this in the visibility and layout of the overlay.
-class InstantOverlayControllerViews : public InstantOverlayController {
- public:
-  InstantOverlayControllerViews(Browser* browser,
-                                OverlayContainer* overlay_container);
-  virtual ~InstantOverlayControllerViews();
-
-  views::WebView* overlay() { return overlay_.get(); }
-
-  views::WebView* release_overlay() WARN_UNUSED_RESULT {
-    return overlay_.release();
-  }
-
- private:
-  // Overridden from InstantOverlayController:
-  virtual void OverlayStateChanged(const InstantOverlayModel& model) OVERRIDE;
-
-  OverlayContainer* const overlay_container_;
-
-  // The view that contains the Instant overlay web contents.
-  scoped_ptr<views::WebView> overlay_;
-
-  DISALLOW_COPY_AND_ASSIGN(InstantOverlayControllerViews);
-};
-
-#endif  // CHROME_BROWSER_UI_VIEWS_FRAME_INSTANT_OVERLAY_CONTROLLER_VIEWS_H_
diff --git a/chrome/browser/ui/views/frame/overlay_container.cc b/chrome/browser/ui/views/frame/overlay_container.cc
deleted file mode 100644
index 317e568..0000000
--- a/chrome/browser/ui/views/frame/overlay_container.cc
+++ /dev/null
@@ -1,314 +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/views/frame/overlay_container.h"
-
-#include "chrome/browser/themes/theme_properties.h"
-#include "chrome/browser/ui/views/bookmarks/bookmark_bar_view.h"
-#include "chrome/browser/ui/views/detachable_toolbar_view.h"
-#include "chrome/browser/ui/views/frame/browser_view.h"
-#include "chrome/browser/ui/views/frame/immersive_mode_controller.h"
-#include "content/public/browser/notification_service.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_view.h"
-#include "grit/theme_resources.h"
-#include "ui/base/resource/resource_bundle.h"
-#include "ui/gfx/canvas.h"
-#include "ui/gfx/image/image_skia.h"
-#include "ui/views/controls/webview/webview.h"
-
-#if defined(USE_AURA)
-#include "ui/aura/window.h"
-#endif  // USE_AURA
-
-namespace {
-
-const int kToolbarOverlap = views::NonClientFrameView::kClientEdgeThickness +
-                            BookmarkBarView::kToolbarAttachedBookmarkBarOverlap;
-
-bool IsFullHeight(int height, InstantSizeUnits units) {
-  return height == 100 && units == INSTANT_SIZE_PERCENT;
-}
-
-int OverlayHeightInPixels(int parent_height, int overlay_height,
-                          InstantSizeUnits overlay_height_units) {
-  parent_height = std::max(0, parent_height);
-  overlay_height = std::max(0, overlay_height);
-  switch (overlay_height_units) {
-    case INSTANT_SIZE_PERCENT:
-      return std::min(parent_height, (parent_height * overlay_height) / 100);
-
-    case INSTANT_SIZE_PIXELS:
-      return std::min(parent_height, overlay_height);
-  }
-  NOTREACHED() << "unknown units: " << overlay_height_units;
-  return 0;
-}
-
-// This class draws the drop shadow below the overlay when the non-NTP overlay
-// doesn't fill up the entire content page.
-// This class is owned by OverlayContainer, which:
-// - adds it as child when shadow is needed
-// - removes it as child when shadow is not needed or when overlay is nuked or
-//   when overlay is removed as child
-class ShadowView : public views::View {
- public:
-  ShadowView() {
-    drop_shadow_ = *ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
-        IDR_OVERLAY_DROP_SHADOW);
-
-    SetPaintToLayer(true);
-    SetFillsBoundsOpaquely(false);
-    set_owned_by_client();
-  }
-
-  virtual ~ShadowView() {}
-
-  virtual gfx::Size GetPreferredSize() OVERRIDE {
-    // Only height really matters, since images will be stretched horizontally
-    // across.
-    return drop_shadow_.size();
-  }
-
-  virtual const char* GetClassName() const OVERRIDE {
-    return "OverlayDropShadow";
-  }
-
- protected:
-  virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE {
-    // Stretch drop shadow horizontally across.
-    canvas->DrawImageInt(
-        drop_shadow_,
-        0, 0, drop_shadow_.width(), drop_shadow_.height(),
-        0, 0, width(), drop_shadow_.height(),
-        true);
-  }
-
- private:
-  gfx::ImageSkia drop_shadow_;
-
-  DISALLOW_COPY_AND_ASSIGN(ShadowView);
-};
-
-}  // namespace
-
-OverlayContainer::OverlayContainer(
-    BrowserView* browser_view,
-    ImmersiveModeController* immersive_mode_controller)
-    : browser_view_(browser_view),
-      immersive_mode_controller_(immersive_mode_controller),
-      overlay_(NULL),
-      overlay_web_contents_(NULL),
-      draw_drop_shadow_(false),
-      overlay_height_(0),
-      overlay_height_units_(INSTANT_SIZE_PIXELS) {
-}
-
-OverlayContainer::~OverlayContainer() {
-}
-
-void OverlayContainer::ResetOverlayAndContents() {
-  // Since |overlay_| will be nuked, shadow view is not needed anymore.
-  shadow_view_.reset();
-  overlay_ = NULL;
-  overlay_web_contents_ = NULL;
-  // Allow top views to close in immersive fullscreen.
-  immersive_revealed_lock_.reset();
-  // Unregister from observing previous |overlay_web_contents_|.
-  registrar_.RemoveAll();
-}
-
-void OverlayContainer::SetOverlay(views::WebView* overlay,
-                                  content::WebContents* overlay_web_contents,
-                                  int height,
-                                  InstantSizeUnits units,
-                                  bool draw_drop_shadow) {
-  // If drawing drop shadow, clip the bottom 1-px-thick separator out of
-  // overlay.
-  // TODO(kuan): remove this when GWS gives chrome the height without the
-  // separator.
-#if !defined(OS_WIN)
-  if (draw_drop_shadow)
-    --height;
-#endif  // !defined(OS_WIN)
-
-  if (overlay_ == overlay && overlay_web_contents_ == overlay_web_contents &&
-      overlay_height_ == height && overlay_height_units_ == units &&
-      draw_drop_shadow_ == draw_drop_shadow) {
-    return;
-  }
-
-  bool repaint_infobars = false;
-
-  if (overlay_ != overlay) {
-    if (overlay_) {
-      RemoveChildView(overlay_);
-    } else {
-      // There's no previous overlay, repaint infobars when showing the new one.
-      repaint_infobars = true;
-    }
-
-    overlay_ = overlay;
-    if (overlay_) {
-      AddChildView(overlay_);
-      // Hold the top views open in immersive fullscreen.
-      immersive_revealed_lock_.reset(
-          immersive_mode_controller_->GetRevealedLock(
-              ImmersiveModeController::ANIMATE_REVEAL_NO));
-    } else {
-      // There's no more overlay, repaint infobars that were obscured by the
-      // previous overlay.
-      repaint_infobars = true;
-      // Allow top views to close in immersive fullscreen.
-      immersive_revealed_lock_.reset();
-    }
-  }
-
-  if (overlay_web_contents_ != overlay_web_contents) {
-    // Unregister from observing previous |overlay_web_contents_|.
-    registrar_.RemoveAll();
-
-    overlay_web_contents_ = overlay_web_contents;
-
-#if !defined(OS_WIN)
-    // Register to new overlay web contents' render view host.
-    if (overlay_web_contents_) {
-      content::RenderViewHost* rvh = overlay_web_contents_->GetRenderViewHost();
-      DCHECK(rvh);
-      if (rvh) {
-        content::NotificationSource source =
-            content::Source<content::RenderWidgetHost>(rvh);
-        registrar_.Add(this,
-            content::NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE,
-            source);
-      }
-    }
-#endif  // !defined(OS_WIN)
-  }
-
-  overlay_height_ = height;
-  overlay_height_units_ = units;
-  draw_drop_shadow_ = draw_drop_shadow;
-
-  // Add shadow view if there's overlay and drop shadow is needed.
-  // Remove shadow view if there's no overlay.
-  // If there's overlay and drop shadow is not needed, that means the partial-
-  // height overlay is going to be full-height.  Don't remove the shadow view
-  // yet because its view will disappear noticeably faster than the webview-ed
-  // overlay is repainted at the full height - when resizing web contents page,
-  // RenderWidgetHostViewAura locks the compositor until texture is updated or
-  // timeout occurs.  This out-of-sync refresh results in a split second where
-  // there's no separator between the overlay and active contents, making the
-  // overlay contents erroneously appear to be part of active contents.
-  // When the overlay is repainted at the full height, we'll be notified via
-  // NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKGING_STORE, at which time
-  // the shadow view will be removed.
-  if (overlay_ && draw_drop_shadow_) {
-#if !defined(OS_WIN)
-    if (!shadow_view_.get()) {
-      // Shadow view has not been created.
-      shadow_view_.reset(new ShadowView());
-      AddChildView(shadow_view_.get());
-    }
-#endif  // !defined(OS_WIN)
-  } else if (!overlay_) {
-    shadow_view_.reset();
-  }
-
-  // Force re-layout of parent and/or re-layout of infobars.
-  browser_view_->OnOverlayStateChanged(repaint_infobars);
-}
-
-gfx::Rect OverlayContainer::GetOverlayBounds() const {
-  gfx::Point screen_loc;
-  ConvertPointToScreen(this, &screen_loc);
-  return gfx::Rect(screen_loc, size());
-}
-
-bool OverlayContainer::WillOverlayBeFullHeight(
-    int overlay_height,
-    InstantSizeUnits overlay_height_units) const {
-  return IsFullHeight(overlay_height, overlay_height_units);
-}
-
-bool OverlayContainer::IsOverlayFullHeight() const {
-  return overlay_ && IsFullHeight(overlay_height_, overlay_height_units_);
-}
-
-gfx::Size OverlayContainer::GetPreferredSize() {
-  if (!overlay_)
-    return gfx::Size();
-  // Make sure IsOverlayFullHeight() is called before this function, because
-  // when overlay is full height, its height is determined by its parent
-  // (i.e. whatever is available from below toolbar), which is not yet known
-  // now.
-  DCHECK(!IsOverlayFullHeight());
-  // Width doesn't matter.
-  // Height includes overlap with toolbar, |overlay_|'s height and, if
-  // necessary, |shadow_view_|'s height.
-  gfx::Size preferred_size(0, kToolbarOverlap + overlay_height_);
-  if (shadow_view_)
-    preferred_size.Enlarge(0, shadow_view_->GetPreferredSize().height());
-  return preferred_size;
-}
-
-void OverlayContainer::Layout() {
-  if (!overlay_)
-    return;
-  int target_overlay_height = OverlayHeightInPixels(
-      height() - kToolbarOverlap, overlay_height_, overlay_height_units_);
-  overlay_->SetBounds(0, kToolbarOverlap, width(), target_overlay_height);
-  if (draw_drop_shadow_) {
-#if !defined(OS_WIN)
-    DCHECK(shadow_view_.get() && shadow_view_->parent());
-    shadow_view_->SetBounds(0, overlay_->bounds().bottom(), width(),
-                            shadow_view_->GetPreferredSize().height());
-#endif  // !defined(OS_WIN)
-  }
-
-  // Need to invoke views::View in case any views whose bounds didn't change
-  // still need a layout.
-  views::View::Layout();
-}
-
-void OverlayContainer::OnPaint(gfx::Canvas* canvas) {
-  // Paint the region which overlaps with the toolbar as a continuation of the
-  // toolbar, like attached bookmark bar does.
-  gfx::Rect toolbar_background_bounds(width(),
-      BookmarkBarView::kToolbarAttachedBookmarkBarOverlap);
-  gfx::Point background_image_offset =
-      browser_view_->OffsetPointForToolbarBackgroundImage(
-          gfx::Point(GetMirroredX(), y()));
-  DetachableToolbarView::PaintBackgroundAttachedMode(canvas, GetThemeProvider(),
-      toolbar_background_bounds, background_image_offset,
-      browser_view_->browser()->host_desktop_type());
-  // Paint a separator below toolbar.
-  canvas->FillRect(
-      gfx::Rect(0,
-                BookmarkBarView::kToolbarAttachedBookmarkBarOverlap,
-                width(),
-                views::NonClientFrameView::kClientEdgeThickness),
-      ThemeProperties::GetDefaultColor(
-          ThemeProperties::COLOR_TOOLBAR_SEPARATOR));
-}
-
-const char* OverlayContainer::GetClassName() const {
-  return "OverlayContainer";
-}
-
-void OverlayContainer::Observe(int type,
-                               const content::NotificationSource& source,
-                               const content::NotificationDetails& details) {
-  DCHECK_EQ(content::NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE,
-            type);
-  // Remove shadow view if it's not needed.
-  if (overlay_ && !draw_drop_shadow_) {
-    DCHECK(overlay_web_contents_);
-    DCHECK_EQ(overlay_web_contents_->GetRenderViewHost(),
-              (content::Source<content::RenderWidgetHost>(source)).ptr());
-    shadow_view_.reset();
-  }
-}
diff --git a/chrome/browser/ui/views/frame/overlay_container.h b/chrome/browser/ui/views/frame/overlay_container.h
deleted file mode 100644
index 9646e6a..0000000
--- a/chrome/browser/ui/views/frame/overlay_container.h
+++ /dev/null
@@ -1,116 +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_VIEWS_FRAME_OVERLAY_CONTAINER_H_
-#define CHROME_BROWSER_UI_VIEWS_FRAME_OVERLAY_CONTAINER_H_
-
-#include <string>
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "base/memory/scoped_ptr.h"
-#include "chrome/common/instant_types.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
-#include "ui/views/view.h"
-
-class BrowserView;
-class ImmersiveModeController;
-class ImmersiveRevealedLock;
-
-namespace content {
-class WebContents;
-}
-
-namespace gfx {
-class Canvas;
-class Rect;
-}
-
-namespace views {
-class WebView;
-};
-
-// OverlayContainer is responsible for managing the overlay WebContents view.
-// OverlayContainer has up to two children: one for Instant's WebContents and,
-// if necessary, one for the drop shadow below it in the y-axis.
-class OverlayContainer : public views::View,
-                         public content::NotificationObserver {
- public:
-  OverlayContainer(BrowserView* browser_view,
-                   ImmersiveModeController* immersive_mode_controller);
-  virtual ~OverlayContainer();
-
-  // Sets the overlay view. This does not delete the old.
-  void SetOverlay(views::WebView* overlay,
-                  content::WebContents* overlay_web_contents,
-                  int height,
-                  InstantSizeUnits units,
-                  bool draw_drop_shadow);
-
-  // Called after overlay view has been reparented to |ContentsContainer| and
-  // has been made the active view.
-  void ResetOverlayAndContents();
-
-  // Returns the bounds the overlay would be shown at.
-  gfx::Rect GetOverlayBounds() const;
-
-  // Returns true if overlay will occupy full height of available space based on
-  // |overlay_height| and |overlay_height_units|.
-  bool WillOverlayBeFullHeight(int overlay_height,
-                               InstantSizeUnits overlay_height_units) const;
-
-  // Returns true if |overlay_| is not NULL and it is occupying full height of
-  // available space.  Must be called before GetPreferredSize(), and only call
-  // the latter if this returns false.
-  bool IsOverlayFullHeight() const;
-
-  content::WebContents* overlay_web_contents() const {
-    return overlay_web_contents_;
-  }
-
-  // Overridden from views::View:
-  // GetPreferredSize() must only be called if IsOverlayFullHeight() returns
-  // false; if overlay is full height, height of OverlayContainer can only be
-  // determined by the parent's height, not here.
-  virtual gfx::Size GetPreferredSize() OVERRIDE;
-  virtual void Layout() OVERRIDE;
-  virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
-  virtual const char* GetClassName() const OVERRIDE;
-
-  // Testing interface:
-  views::WebView* GetOverlayWebViewForTest() { return overlay_; }
-
- private:
-  // content::NotificationObserver implementation.
-  virtual void Observe(int type,
-                       const content::NotificationSource& source,
-                       const content::NotificationDetails& details) OVERRIDE;
-
-  BrowserView* const browser_view_;
-  ImmersiveModeController* immersive_mode_controller_;
-
-  // Used to force the top views open while in immersive fullscreen.
-  scoped_ptr<ImmersiveRevealedLock> immersive_revealed_lock_;
-
-  // Owned by |InstantOverlayControllerViews|.
-  views::WebView* overlay_;
-
-  // Owned by |IntantController| if not NULL, else |InstantModel|.
-  content::WebContents* overlay_web_contents_;
-
-  // Drop shadow below partial-height |overlay_|.
-  scoped_ptr<views::View> shadow_view_;
-  bool draw_drop_shadow_;
-
-  // The desired height of the overlay and units.
-  int overlay_height_;
-  InstantSizeUnits overlay_height_units_;
-
-  content::NotificationRegistrar registrar_;
-
-  DISALLOW_COPY_AND_ASSIGN(OverlayContainer);
-};
-
-#endif  // CHROME_BROWSER_UI_VIEWS_FRAME_OVERLAY_CONTAINER_H_
diff --git a/chrome/browser/ui/views/infobars/OWNERS b/chrome/browser/ui/views/infobars/OWNERS
new file mode 100644
index 0000000..bf426d6
--- /dev/null
+++ b/chrome/browser/ui/views/infobars/OWNERS
@@ -0,0 +1 @@
+pkasting@chromium.org
diff --git a/chrome/browser/ui/views/infobars/alternate_nav_infobar_view.cc b/chrome/browser/ui/views/infobars/alternate_nav_infobar_view.cc
index c76b933..87ad887 100644
--- a/chrome/browser/ui/views/infobars/alternate_nav_infobar_view.cc
+++ b/chrome/browser/ui/views/infobars/alternate_nav_infobar_view.cc
@@ -10,12 +10,14 @@
 #include "ui/views/controls/label.h"
 #include "ui/views/controls/link.h"
 
+
 // AlternateNavInfoBarDelegate -------------------------------------------------
 
 InfoBar* AlternateNavInfoBarDelegate::CreateInfoBar(InfoBarService* owner) {
   return new AlternateNavInfoBarView(owner, this);
 }
 
+
 // AlternateNavInfoBarView -----------------------------------------------------
 
 AlternateNavInfoBarView::AlternateNavInfoBarView(
diff --git a/chrome/browser/ui/views/infobars/confirm_infobar.cc b/chrome/browser/ui/views/infobars/confirm_infobar.cc
index 68e775f..82da528 100644
--- a/chrome/browser/ui/views/infobars/confirm_infobar.cc
+++ b/chrome/browser/ui/views/infobars/confirm_infobar.cc
@@ -11,12 +11,14 @@
 #include "ui/views/controls/label.h"
 #include "ui/views/controls/link.h"
 
+
 // ConfirmInfoBarDelegate -----------------------------------------------------
 
 InfoBar* ConfirmInfoBarDelegate::CreateInfoBar(InfoBarService* owner) {
   return new ConfirmInfoBar(owner, this);
 }
 
+
 // ConfirmInfoBar -------------------------------------------------------------
 
 ConfirmInfoBar::ConfirmInfoBar(InfoBarService* owner,
diff --git a/chrome/browser/ui/views/infobars/extension_infobar.cc b/chrome/browser/ui/views/infobars/extension_infobar.cc
index 6c2e220..a555909 100644
--- a/chrome/browser/ui/views/infobars/extension_infobar.cc
+++ b/chrome/browser/ui/views/infobars/extension_infobar.cc
@@ -30,7 +30,7 @@
 // ExtensionInfoBarDelegate ----------------------------------------------------
 
 InfoBar* ExtensionInfoBarDelegate::CreateInfoBar(InfoBarService* owner) {
-  return new ExtensionInfoBar(browser_, owner, this);
+  return new ExtensionInfoBar(owner, this, browser_);
 }
 
 
@@ -78,9 +78,9 @@
 
 }  // namespace
 
-ExtensionInfoBar::ExtensionInfoBar(Browser* browser,
-                                   InfoBarService* owner,
-                                   ExtensionInfoBarDelegate* delegate)
+ExtensionInfoBar::ExtensionInfoBar(InfoBarService* owner,
+                                   ExtensionInfoBarDelegate* delegate,
+                                   Browser* browser)
     : InfoBarView(owner, delegate),
       delegate_(delegate),
       browser_(browser),
@@ -88,9 +88,9 @@
       icon_as_menu_(NULL),
       icon_as_image_(NULL),
       weak_ptr_factory_(this) {
-  delegate->set_observer(this);
+  GetDelegate()->set_observer(this);
 
-  int height = delegate->height();
+  int height = GetDelegate()->height();
   SetBarTargetHeight((height > 0) ? (height + kSeparatorLineHeight) : 0);
 }
 
@@ -173,8 +173,8 @@
                                            const gfx::Point& point) {
   if (!owner())
     return;  // We're closing; don't call anything, it might access the owner.
-  const extensions::Extension* extension = GetDelegate()->extension_host()->
-      extension();
+  const extensions::Extension* extension =
+      GetDelegate()->extension_host()->extension();
   DCHECK(icon_as_menu_);
 
   scoped_refptr<ExtensionContextMenuModel> options_menu_contents =
diff --git a/chrome/browser/ui/views/infobars/extension_infobar.h b/chrome/browser/ui/views/infobars/extension_infobar.h
index ce5e550..930c714 100644
--- a/chrome/browser/ui/views/infobars/extension_infobar.h
+++ b/chrome/browser/ui/views/infobars/extension_infobar.h
@@ -20,9 +20,9 @@
                          public ExtensionInfoBarDelegate::DelegateObserver,
                          public views::MenuButtonListener {
  public:
-  ExtensionInfoBar(Browser* browser,
-                   InfoBarService* owner,
-                   ExtensionInfoBarDelegate* delegate);
+  ExtensionInfoBar(InfoBarService* owner,
+                   ExtensionInfoBarDelegate* delegate,
+                   Browser* browser);
 
  private:
   virtual ~ExtensionInfoBar();
diff --git a/chrome/browser/ui/views/infobars/infobar_view.cc b/chrome/browser/ui/views/infobars/infobar_view.cc
index 1208c6a..0936c95 100644
--- a/chrome/browser/ui/views/infobars/infobar_view.cc
+++ b/chrome/browser/ui/views/infobars/infobar_view.cc
@@ -61,7 +61,7 @@
       icon_(NULL),
       close_button_(NULL) {
   set_owned_by_client();  // InfoBar deletes itself at the appropriate time.
-  set_background(new InfoBarBackground(delegate->GetInfoBarType()));
+  set_background(new InfoBarBackground(InfoBar::delegate()->GetInfoBarType()));
 }
 
 InfoBarView::~InfoBarView() {
@@ -355,7 +355,7 @@
   if (delegate()) {
     state->name = l10n_util::GetStringUTF16(
         (delegate()->GetInfoBarType() == InfoBarDelegate::WARNING_TYPE) ?
-        IDS_ACCNAME_INFOBAR_WARNING : IDS_ACCNAME_INFOBAR_PAGE_ACTION);
+            IDS_ACCNAME_INFOBAR_WARNING : IDS_ACCNAME_INFOBAR_PAGE_ACTION);
   }
   state->role = ui::AccessibilityTypes::ROLE_ALERT;
 }
diff --git a/chrome/browser/ui/views/infobars/translate_infobar_base.cc b/chrome/browser/ui/views/infobars/translate_infobar_base.cc
index 7683c2c..03a8738 100644
--- a/chrome/browser/ui/views/infobars/translate_infobar_base.cc
+++ b/chrome/browser/ui/views/infobars/translate_infobar_base.cc
@@ -16,6 +16,7 @@
 #include "ui/views/controls/button/menu_button.h"
 #include "ui/views/controls/label.h"
 
+
 // TranslateInfoBarDelegate ---------------------------------------------------
 
 InfoBar* TranslateInfoBarDelegate::CreateInfoBar(InfoBarService* owner) {
@@ -26,6 +27,7 @@
   return new TranslateMessageInfoBar(owner, this);
 }
 
+
 // TranslateInfoBarBase -------------------------------------------------------
 
 // static
@@ -103,7 +105,7 @@
 }
 
 const views::Background& TranslateInfoBarBase::GetBackground() {
-  return GetDelegate()->IsError() ? error_background_ : *background();
+  return GetDelegate()->is_error() ? error_background_ : *background();
 }
 
 void TranslateInfoBarBase::FadeBackground(gfx::Canvas* canvas,
diff --git a/chrome/browser/ui/views/infobars/translate_infobar_base.h b/chrome/browser/ui/views/infobars/translate_infobar_base.h
index d8ff765..617173f 100644
--- a/chrome/browser/ui/views/infobars/translate_infobar_base.h
+++ b/chrome/browser/ui/views/infobars/translate_infobar_base.h
@@ -24,8 +24,6 @@
                                 const string16& text);
 
  protected:
-  static const int kButtonInLabelSpacing;
-
   TranslateInfoBarBase(InfoBarService* owner,
                        TranslateInfoBarDelegate* delegate);
   virtual ~TranslateInfoBarBase();
@@ -37,6 +35,8 @@
   // Convenience to retrieve the TranslateInfoBarDelegate for this infobar.
   TranslateInfoBarDelegate* GetDelegate();
 
+  static const int kButtonInLabelSpacing;
+
  private:
   // InfoBarView:
   virtual void OnPaintBackground(gfx::Canvas* canvas) OVERRIDE;
diff --git a/chrome/browser/ui/views/location_bar/OWNERS b/chrome/browser/ui/views/location_bar/OWNERS
new file mode 100644
index 0000000..bf426d6
--- /dev/null
+++ b/chrome/browser/ui/views/location_bar/OWNERS
@@ -0,0 +1 @@
+pkasting@chromium.org
diff --git a/chrome/browser/ui/views/location_bar/action_box_button_view.cc b/chrome/browser/ui/views/location_bar/action_box_button_view.cc
deleted file mode 100644
index 89dd94e..0000000
--- a/chrome/browser/ui/views/location_bar/action_box_button_view.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/ui/views/location_bar/action_box_button_view.h"
-
-#include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/toolbar/action_box_menu_model.h"
-#include "chrome/browser/ui/view_ids.h"
-#include "chrome/browser/ui/views/action_box_menu.h"
-#include "chrome/browser/ui/views/location_bar/location_bar_view.h"
-#include "grit/generated_resources.h"
-#include "grit/theme_resources.h"
-#include "ui/base/accessibility/accessible_view_state.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "ui/base/resource/resource_bundle.h"
-#include "ui/gfx/path.h"
-
-ActionBoxButtonView::ActionBoxButtonView(Browser* browser,
-                                         const gfx::Point& menu_offset)
-    : views::MenuButton(NULL, string16(), this, false),
-      browser_(browser),
-      menu_offset_(menu_offset),
-      controller_(browser, this) {
-  set_id(VIEW_ID_ACTION_BOX_BUTTON);
-  SetTooltipText(l10n_util::GetStringUTF16(IDS_TOOLTIP_ACTION_BOX_BUTTON));
-  SetIcon(*ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
-      IDR_ACTION_BOX_BUTTON_NORMAL));
-  SetHoverIcon(*ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
-      IDR_ACTION_BOX_BUTTON_HOVER));
-  SetPushedIcon(*ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
-      IDR_ACTION_BOX_BUTTON_PRESSED));
-  set_accessibility_focusable(true);
-  set_border(NULL);
-  SizeToPreferredSize();
-}
-
-ActionBoxButtonView::~ActionBoxButtonView() {
-}
-
-int ActionBoxButtonView::GetBuiltInHorizontalPadding() const {
-  return GetBuiltInHorizontalPaddingImpl();
-}
-
-void ActionBoxButtonView::GetAccessibleState(ui::AccessibleViewState* state) {
-  MenuButton::GetAccessibleState(state);
-  state->name = l10n_util::GetStringUTF16(IDS_ACCNAME_ACTION_BOX_BUTTON);
-}
-
-void ActionBoxButtonView::OnMenuButtonClicked(View* source,
-                                              const gfx::Point& point) {
-  controller_.OnButtonClicked();
-}
-
-void ActionBoxButtonView::ShowMenu(scoped_ptr<ActionBoxMenuModel> menu_model) {
-  menu_ = ActionBoxMenu::Create(browser_, menu_model.Pass());
-  menu_->RunMenu(this, menu_offset_);
-}
diff --git a/chrome/browser/ui/views/location_bar/action_box_button_view.h b/chrome/browser/ui/views/location_bar/action_box_button_view.h
deleted file mode 100644
index f3d02de..0000000
--- a/chrome/browser/ui/views/location_bar/action_box_button_view.h
+++ /dev/null
@@ -1,55 +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_VIEWS_LOCATION_BAR_ACTION_BOX_BUTTON_VIEW_H_
-#define CHROME_BROWSER_UI_VIEWS_LOCATION_BAR_ACTION_BOX_BUTTON_VIEW_H_
-
-#include "base/memory/scoped_ptr.h"
-#include "chrome/browser/ui/toolbar/action_box_button_controller.h"
-#include "chrome/browser/ui/views/location_bar/touchable_location_bar_view.h"
-#include "ui/views/controls/button/menu_button.h"
-#include "ui/views/controls/button/menu_button_listener.h"
-
-class ActionBoxMenu;
-class Browser;
-
-// ActionBoxButtonView displays a plus button with associated menu.
-class ActionBoxButtonView : public views::MenuButton,
-                            public views::MenuButtonListener,
-                            public ActionBoxButtonController::Delegate,
-                            public TouchableLocationBarView {
- public:
-  ActionBoxButtonView(Browser* browser, const gfx::Point& menu_offset);
-  virtual ~ActionBoxButtonView();
-
-  ActionBoxButtonController* action_box_button_controller() {
-   return &controller_;
-  }
-
-  // TouchableLocationBarView:
-  virtual int GetBuiltInHorizontalPadding() const OVERRIDE;
-
- private:
-  // Overridden from views::CustomButton:
-  virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
-
-  // Overridden from views::MenuButtonListener:
-  virtual void OnMenuButtonClicked(View* source,
-                                   const gfx::Point& point) OVERRIDE;
-
-  // Overridden from ActionBoxButtonController::Delegate:
-  virtual void ShowMenu(scoped_ptr<ActionBoxMenuModel> menu_model) OVERRIDE;
-
-  Browser* browser_;
-
-  gfx::Point menu_offset_;
-
-  ActionBoxButtonController controller_;
-
-  scoped_ptr<ActionBoxMenu> menu_;
-
-  DISALLOW_COPY_AND_ASSIGN(ActionBoxButtonView);
-};
-
-#endif  // CHROME_BROWSER_UI_VIEWS_LOCATION_BAR_ACTION_BOX_BUTTON_VIEW_H_
diff --git a/chrome/browser/ui/views/location_bar/location_bar_view.cc b/chrome/browser/ui/views/location_bar/location_bar_view.cc
index 4016fd8..352f878 100644
--- a/chrome/browser/ui/views/location_bar/location_bar_view.cc
+++ b/chrome/browser/ui/views/location_bar/location_bar_view.cc
@@ -38,7 +38,6 @@
 #include "chrome/browser/ui/views/bookmarks/bookmark_prompt_view.h"
 #include "chrome/browser/ui/views/browser_dialogs.h"
 #include "chrome/browser/ui/views/extensions/extension_popup.h"
-#include "chrome/browser/ui/views/location_bar/action_box_button_view.h"
 #include "chrome/browser/ui/views/location_bar/autofill_credit_card_view.h"
 #include "chrome/browser/ui/views/location_bar/content_setting_image_view.h"
 #include "chrome/browser/ui/views/location_bar/ev_bubble_view.h"
@@ -76,6 +75,7 @@
 #include "ui/gfx/image/image.h"
 #include "ui/gfx/image/image_skia_operations.h"
 #include "ui/gfx/skia_util.h"
+#include "ui/native_theme/native_theme.h"
 #include "ui/views/background.h"
 #include "ui/views/border.h"
 #include "ui/views/button_drag_utils.h"
@@ -96,7 +96,6 @@
 
 #if !defined(OS_CHROMEOS)
 #include "chrome/browser/ui/views/first_run_bubble.h"
-#include "ui/native_theme/native_theme.h"
 #endif
 
 #if defined(USE_AURA)
@@ -187,7 +186,6 @@
       open_pdf_in_reader_view_(NULL),
       script_bubble_icon_view_(NULL),
       star_view_(NULL),
-      action_box_button_view_(NULL),
       is_popup_mode_(is_popup_mode),
       show_focus_rect_(false),
       template_url_service_(NULL),
@@ -343,14 +341,6 @@
   star_view_->SetVisible(false);
   AddChildView(star_view_);
 
-  if (extensions::FeatureSwitch::action_box()->IsEnabled() && !is_popup_mode_ &&
-      browser_) {
-    action_box_button_view_ = new ActionBoxButtonView(
-        browser_,
-        gfx::Point(GetHorizontalEdgeThickness(), vertical_edge_thickness()));
-    AddChildView(action_box_button_view_);
-  }
-
   registrar_.Add(this,
                  chrome::NOTIFICATION_EXTENSION_LOCATION_BAR_UPDATED,
                  content::Source<Profile>(profile_));
@@ -487,12 +477,9 @@
   command_updater_->UpdateCommandEnabled(IDC_BOOKMARK_PAGE, star_enabled);
   command_updater_->UpdateCommandEnabled(IDC_BOOKMARK_PAGE_FROM_STAR,
                                          star_enabled);
-  if (star_view_ && !extensions::FeatureSwitch::action_box()->IsEnabled())
+  if (star_view_)
     star_view_->SetVisible(star_enabled);
 
-  if (action_box_button_view_)
-    action_box_button_view_->SetVisible(!model_->GetInputInProgress());
-
   location_entry_->Update(tab_for_state_restoring);
 
   OnChanged();
@@ -588,22 +575,13 @@
 }
 
 void LocationBarView::SetStarToggled(bool on) {
-  if (!star_view_)
-    return;
-  star_view_->SetToggled(on);
-  if (action_box_button_view_ && (star_view_->visible() != on)) {
-    star_view_->SetVisible(on);
-    Layout();
-  }
+  if (star_view_)
+    star_view_->SetToggled(on);
 }
 
 void LocationBarView::ShowBookmarkPrompt() {
-  if (action_box_button_view_) {
-    BookmarkPromptView::ShowPrompt(action_box_button_view_,
-                                   profile_->GetPrefs());
-  } else if (star_view_ && star_view_->visible()) {
+  if (star_view_ && star_view_->visible())
     BookmarkPromptView::ShowPrompt(star_view_, profile_->GetPrefs());
-  }
 }
 
 void LocationBarView::ZoomChangedForActiveTab(bool can_show_bubble) {
@@ -723,7 +701,7 @@
         selected_keyword_view_->set_is_extension_icon(false);
       }
     }
-  } else if (model_->GetSecurityLevel() == ToolbarModel::EV_SECURE) {
+  } else if (model_->GetSecurityLevel(false) == ToolbarModel::EV_SECURE) {
     ev_bubble_view_->SetLabel(model_->GetEVCertName());
     // The largest fraction of the omnibox that can be taken by the EV bubble.
     const double kMaxBubbleFraction = 0.5;
@@ -737,12 +715,6 @@
         location_icon_view_);
   }
 
-  if (action_box_button_view_ && action_box_button_view_->visible()) {
-    trailing_decorations.AddDecoration(
-        vertical_edge_thickness(), location_height,
-        action_box_button_view_->GetBuiltInHorizontalPadding(),
-        action_box_button_view_);
-  }
   if (star_view_ && star_view_->visible()) {
     trailing_decorations.AddDecoration(
         vertical_edge_thickness(), location_height,
@@ -1160,8 +1132,6 @@
       right_anchor = star_view_;
     if (!right_anchor)
       right_anchor = script_bubble_icon_view_;
-    if (!right_anchor)
-      right_anchor = action_box_button_view_;
     DCHECK(right_anchor);
 
     // Add the page actions in reverse order, so that the child views are
@@ -1252,7 +1222,8 @@
     return;
 
   const int32 tab_id = SessionID::IdForTab(web_contents);
-  const ToolbarModel::SecurityLevel security_level = model_->GetSecurityLevel();
+  const ToolbarModel::SecurityLevel security_level =
+      model_->GetSecurityLevel(false);
   const SkColor text_color = GetColor(security_level, TEXT);
   const SkColor background_color = GetColor(security_level, BACKGROUND);
 
@@ -1486,11 +1457,6 @@
   NOTREACHED();
 }
 
-void LocationBarView::TestActionBoxMenuItemSelected(int command_id) {
-  action_box_button_view_->action_box_button_controller()->
-      ExecuteCommand(command_id, 0);
-}
-
 bool LocationBarView::GetBookmarkStarVisibility() {
   DCHECK(star_view_);
   return star_view_->visible();
diff --git a/chrome/browser/ui/views/location_bar/location_bar_view.h b/chrome/browser/ui/views/location_bar/location_bar_view.h
index 0fc5ddf..96151da 100644
--- a/chrome/browser/ui/views/location_bar/location_bar_view.h
+++ b/chrome/browser/ui/views/location_bar/location_bar_view.h
@@ -310,7 +310,6 @@
   virtual ExtensionAction* GetPageAction(size_t index) OVERRIDE;
   virtual ExtensionAction* GetVisiblePageAction(size_t index) OVERRIDE;
   virtual void TestPageActionPressed(size_t index) OVERRIDE;
-  virtual void TestActionBoxMenuItemSelected(int command_id) OVERRIDE;
   virtual bool GetBookmarkStarVisibility() OVERRIDE;
 
   // TemplateURLServiceObserver:
@@ -502,9 +501,6 @@
   // The star.
   StarView* star_view_;
 
-  // The action box button (plus).
-  ActionBoxButtonView* action_box_button_view_;
-
   // Whether we're in popup mode.
   const bool is_popup_mode_;
 
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 eb65227..655bb3a 100644
--- a/chrome/browser/ui/views/message_center/web_notification_tray.cc
+++ b/chrome/browser/ui/views/message_center/web_notification_tray.cc
@@ -281,7 +281,8 @@
   if (!status_tray)
     return NULL;
 
-  StatusIcon* status_icon = status_tray->CreateStatusIcon();
+  StatusIcon* status_icon =
+      status_tray->CreateStatusIcon(StatusTray::NOTIFICATION_TRAY_ICON);
   if (!status_icon)
     return NULL;
 
diff --git a/chrome/browser/ui/views/omnibox/OWNERS b/chrome/browser/ui/views/omnibox/OWNERS
new file mode 100644
index 0000000..bf426d6
--- /dev/null
+++ b/chrome/browser/ui/views/omnibox/OWNERS
@@ -0,0 +1 @@
+pkasting@chromium.org
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
index 0c59dbc..0a5c54f 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
@@ -360,7 +360,7 @@
   bool visibly_changed_permanent_text =
       model()->UpdatePermanentText(toolbar_model()->GetText(true));
   ToolbarModel::SecurityLevel security_level =
-        toolbar_model()->GetSecurityLevel();
+        toolbar_model()->GetSecurityLevel(false);
   bool changed_security_level = (security_level != security_level_);
   security_level_ = security_level;
 
@@ -779,7 +779,7 @@
   if (command_id == IDS_PASTE_AND_GO)
     return model()->CanPasteAndGo(GetClipboardText());
   if (command_id == IDC_COPY_URL) {
-    return toolbar_model()->WouldReplaceSearchURLWithSearchTerms() &&
+    return toolbar_model()->WouldReplaceSearchURLWithSearchTerms(false) &&
       !model()->user_input_in_progress();
   }
   return command_updater()->IsCommandEnabled(command_id);
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_win.cc b/chrome/browser/ui/views/omnibox/omnibox_view_win.cc
index bde208b..d4b80da 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_view_win.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_view_win.cc
@@ -602,7 +602,7 @@
       model()->UpdatePermanentText(toolbar_model()->GetText(true));
 
   const ToolbarModel::SecurityLevel security_level =
-      toolbar_model()->GetSecurityLevel();
+      toolbar_model()->GetSecurityLevel(false);
   const bool changed_security_level = (security_level != security_level_);
 
   // Bail early when no visible state will actually change (prevents an
@@ -1177,7 +1177,7 @@
     case IDC_COPY_URL:
       return !!CanCopy() &&
           !model()->user_input_in_progress() &&
-          toolbar_model()->WouldReplaceSearchURLWithSearchTerms();
+          toolbar_model()->WouldReplaceSearchURLWithSearchTerms(false);
     case IDC_PASTE:
       return !!CanPaste();
     case IDS_PASTE_AND_GO:
diff --git a/chrome/browser/ui/views/status_icons/status_icon_linux_wrapper.cc b/chrome/browser/ui/views/status_icons/status_icon_linux_wrapper.cc
new file mode 100644
index 0000000..f257a3f
--- /dev/null
+++ b/chrome/browser/ui/views/status_icons/status_icon_linux_wrapper.cc
@@ -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.
+
+#include "chrome/browser/ui/views/status_icons/status_icon_linux_wrapper.h"
+
+StatusIconLinuxWrapper::StatusIconLinuxWrapper(StatusIconLinux* status_icon) {
+  status_icon_.reset(status_icon);
+  status_icon_->set_delegate(this);
+}
+
+StatusIconLinuxWrapper::~StatusIconLinuxWrapper() {}
+
+void StatusIconLinuxWrapper::SetImage(const gfx::ImageSkia& image) {
+  status_icon_->SetImage(image);
+}
+
+void StatusIconLinuxWrapper::SetPressedImage(const gfx::ImageSkia& image) {
+  status_icon_->SetPressedImage(image);
+}
+
+void StatusIconLinuxWrapper::SetToolTip(const string16& tool_tip) {
+  status_icon_->SetToolTip(tool_tip);
+}
+
+void StatusIconLinuxWrapper::SetClickActionLabel(const string16& label) {
+  status_icon_->SetClickActionLabel(label);
+}
+
+void StatusIconLinuxWrapper::DisplayBalloon(const gfx::ImageSkia& icon,
+                                            const string16& title,
+                                            const string16& contents) {
+  notification_.DisplayBalloon(icon, title, contents);
+}
+
+void StatusIconLinuxWrapper::OnClick() {
+  DispatchClickEvent();
+}
+
+StatusIconLinuxWrapper* StatusIconLinuxWrapper::CreateWrappedStatusIcon() {
+  const ui::LinuxUI* linux_ui = ui::LinuxUI::instance();
+  if (linux_ui) {
+    scoped_ptr<StatusIconLinux> status_icon = linux_ui->CreateLinuxStatusIcon();
+    if (status_icon.get())
+      return new StatusIconLinuxWrapper(status_icon.release());
+  }
+  return NULL;
+}
+
+void StatusIconLinuxWrapper::UpdatePlatformContextMenu(ui::MenuModel* model) {
+  status_icon_->UpdatePlatformContextMenu(model);
+}
diff --git a/chrome/browser/ui/views/status_icons/status_icon_linux_wrapper.h b/chrome/browser/ui/views/status_icons/status_icon_linux_wrapper.h
new file mode 100644
index 0000000..5bb7dbf
--- /dev/null
+++ b/chrome/browser/ui/views/status_icons/status_icon_linux_wrapper.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_VIEWS_STATUS_ICONS_STATUS_ICON_LINUX_WRAPPER_H_
+#define CHROME_BROWSER_UI_VIEWS_STATUS_ICONS_STATUS_ICON_LINUX_WRAPPER_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "chrome/browser/status_icons/desktop_notification_balloon.h"
+#include "chrome/browser/status_icons/status_icon.h"
+#include "ui/linux_ui/linux_ui.h"
+
+// Wrapper class for StatusIconLinux that implements the standard StatusIcon
+// interface. Also handles callbacks from StatusIconLinux.
+class StatusIconLinuxWrapper : public StatusIcon,
+                               public StatusIconLinux::Delegate {
+ public:
+  virtual ~StatusIconLinuxWrapper();
+
+  // StatusIcon overrides:
+  virtual void SetImage(const gfx::ImageSkia& image) OVERRIDE;
+  virtual void SetPressedImage(const gfx::ImageSkia& image) OVERRIDE;
+  virtual void SetToolTip(const string16& tool_tip) OVERRIDE;
+  virtual void SetClickActionLabel(const string16& label) OVERRIDE;
+  virtual void DisplayBalloon(const gfx::ImageSkia& icon,
+                              const string16& title,
+                              const string16& contents) OVERRIDE;
+
+  // StatusIconLinux::Delegate overrides:
+  virtual void OnClick() OVERRIDE;
+
+  static StatusIconLinuxWrapper* CreateWrappedStatusIcon();
+
+ protected:
+  // StatusIcon overrides:
+  // Invoked after a call to SetContextMenu() to let the platform-specific
+  // subclass update the native context menu based on the new model. If NULL is
+  // passed, subclass should destroy the native context menu.
+  virtual void UpdatePlatformContextMenu(ui::MenuModel* model) OVERRIDE;
+
+ private:
+  // A status icon wrapper should only be created by calling
+  // CreateWrappedStatusIcon().
+  explicit StatusIconLinuxWrapper(StatusIconLinux* status_icon);
+
+  // Notification balloon.
+  DesktopNotificationBalloon notification_;
+  scoped_ptr<StatusIconLinux> status_icon_;
+
+  DISALLOW_COPY_AND_ASSIGN(StatusIconLinuxWrapper);
+};
+
+#endif  // CHROME_BROWSER_UI_VIEWS_STATUS_ICONS_STATUS_ICON_LINUX_WRAPPER_H_
diff --git a/chrome/browser/ui/views/status_icons/status_tray_linux.cc b/chrome/browser/ui/views/status_icons/status_tray_linux.cc
index 9fc274a..2aa06c4 100644
--- a/chrome/browser/ui/views/status_icons/status_tray_linux.cc
+++ b/chrome/browser/ui/views/status_icons/status_tray_linux.cc
@@ -2,9 +2,32 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/status_icons/status_tray.h"
+#include "chrome/browser/ui/views/status_icons/status_tray_linux.h"
 
-// Status icons are not currently supported on linux/views or Aura.
+#ifndef OS_CHROMEOS
+#include "chrome/browser/ui/views/status_icons/status_icon_linux_wrapper.h"
+#include "ui/linux_ui/linux_ui.h"
+
+StatusTrayLinux::StatusTrayLinux() {
+}
+
+StatusTrayLinux::~StatusTrayLinux() {
+}
+
+StatusIcon* StatusTrayLinux::CreatePlatformStatusIcon(StatusIconType type) {
+  return StatusIconLinuxWrapper::CreateWrappedStatusIcon();
+}
+
+StatusTray* StatusTray::Create() {
+  const ui::LinuxUI* linux_ui = ui::LinuxUI::instance();
+
+  // Only create a status tray if we can actually create status icons.
+  if (linux_ui && linux_ui->IsStatusIconSupported())
+    return new StatusTrayLinux();
+  return NULL;
+}
+#else
 StatusTray* StatusTray::Create() {
   return NULL;
 }
+#endif
diff --git a/chrome/browser/ui/views/status_icons/status_tray_linux.h b/chrome/browser/ui/views/status_icons/status_tray_linux.h
new file mode 100644
index 0000000..ea38ae5
--- /dev/null
+++ b/chrome/browser/ui/views/status_icons/status_tray_linux.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_UI_VIEWS_STATUS_ICONS_STATUS_TRAY_LINUX_H_
+#define CHROME_BROWSER_UI_VIEWS_STATUS_ICONS_STATUS_TRAY_LINUX_H_
+
+#include "base/compiler_specific.h"
+#include "chrome/browser/status_icons/status_tray.h"
+
+class StatusTrayLinux : public StatusTray {
+ public:
+  StatusTrayLinux();
+  virtual ~StatusTrayLinux();
+
+ protected:
+  // Overriden from StatusTray:
+  virtual StatusIcon* CreatePlatformStatusIcon(StatusIconType type) OVERRIDE;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(StatusTrayLinux);
+};
+
+#endif  // CHROME_BROWSER_UI_VIEWS_STATUS_ICONS_STATUS_TRAY_LINUX_H_
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 97792f7..8df1cf5 100644
--- a/chrome/browser/ui/views/status_icons/status_tray_win.cc
+++ b/chrome/browser/ui/views/status_icons/status_tray_win.cc
@@ -15,6 +15,15 @@
 
 static const UINT kStatusIconMessage = WM_APP + 1;
 
+namespace {
+// |kBaseIconId| is 2 to avoid conflicts with plugins that hard-code id 1.
+const UINT kBaseIconId = 2;
+
+UINT ReservedIconId(StatusTray::StatusIconType type) {
+  return kBaseIconId + static_cast<UINT>(type);
+}
+}  // namespace
+
 StatusTrayWin::StatusTrayWin()
     : next_icon_id_(1),
       atom_(0),
@@ -110,12 +119,22 @@
     UnregisterClass(MAKEINTATOM(atom_), instance_);
 }
 
-StatusIcon* StatusTrayWin::CreatePlatformStatusIcon() {
-  if (win8::IsSingleWindowMetroMode()) {
-    return new StatusIconMetro(next_icon_id_++);
-  } else {
-    return new StatusIconWin(next_icon_id_++, window_, kStatusIconMessage);
-  }
+StatusIcon* StatusTrayWin::CreatePlatformStatusIcon(
+    StatusTray::StatusIconType type) {
+  UINT next_icon_id;
+  if (type == StatusTray::OTHER_ICON)
+    next_icon_id = NextIconId();
+  else
+    next_icon_id = ReservedIconId(type);
+
+  if (win8::IsSingleWindowMetroMode())
+    return new StatusIconMetro(next_icon_id);
+  return new StatusIconWin(next_icon_id, window_, kStatusIconMessage);
+}
+
+UINT StatusTrayWin::NextIconId() {
+  UINT icon_id = next_icon_id_++;
+  return kBaseIconId + static_cast<UINT>(NAMED_STATUS_ICON_COUNT) + icon_id;
 }
 
 StatusTray* StatusTray::Create() {
diff --git a/chrome/browser/ui/views/status_icons/status_tray_win.h b/chrome/browser/ui/views/status_icons/status_tray_win.h
index ba03e8f..87974f0 100644
--- a/chrome/browser/ui/views/status_icons/status_tray_win.h
+++ b/chrome/browser/ui/views/status_icons/status_tray_win.h
@@ -20,9 +20,10 @@
                            UINT message,
                            WPARAM wparam,
                            LPARAM lparam);
+
  protected:
   // Overriden from StatusTray:
-  virtual StatusIcon* CreatePlatformStatusIcon() OVERRIDE;
+  virtual StatusIcon* CreatePlatformStatusIcon(StatusIconType type) OVERRIDE;
 
  private:
   // Static callback invoked when a message comes in to our messaging window.
@@ -31,6 +32,8 @@
                                         WPARAM wparam,
                                         LPARAM lparam);
 
+  UINT NextIconId();
+
   // The unique icon ID we will assign to the next icon.
   UINT next_icon_id_;
 
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 3968cdc..b42fd96 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
@@ -43,7 +43,7 @@
   // Create an icon, set the images, tooltip, and context menu, then shut it
   // down.
   StatusTrayWin tray;
-  StatusIcon* icon = tray.CreateStatusIcon();
+  StatusIcon* icon = tray.CreateStatusIcon(StatusTray::OTHER_ICON);
   ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
   gfx::ImageSkia* image = rb.GetImageSkiaNamed(IDR_STATUS_TRAY_ICON);
   icon->SetImage(*image);
@@ -58,7 +58,8 @@
 TEST(StatusTrayWinTest, ClickOnIcon) {
   // Create an icon, send a fake click event, make sure observer is called.
   StatusTrayWin tray;
-  StatusIconWin* icon = static_cast<StatusIconWin*>(tray.CreateStatusIcon());
+  StatusIconWin* icon = static_cast<StatusIconWin*>(
+      tray.CreateStatusIcon(StatusTray::OTHER_ICON));
   FakeStatusIconObserver observer;
   icon->AddObserver(&observer);
   // Mimic a click.
@@ -72,7 +73,8 @@
 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());
+  StatusIconWin* icon = static_cast<StatusIconWin*>(
+      tray.CreateStatusIcon(StatusTray::OTHER_ICON));
   FakeStatusIconObserver observer;
   icon->AddObserver(&observer);
   // Mimic a click.
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 e9183af..3439214 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
@@ -194,12 +194,9 @@
           IDS_ENTERPRISE_SIGNIN_EXPLANATION_WITHOUT_PROFILE_CREATION_NEW_STYLE,
           username, learn_more_text, &offsets);
   explanation_label_ = new views::StyledLabel(signin_explanation_text, this);
-  views::StyledLabel::RangeStyleInfo link_style =
-      views::StyledLabel::RangeStyleInfo::CreateForLink();
-  link_style.font_style = gfx::Font::NORMAL;
   explanation_label_->AddStyleRange(
       ui::Range(offsets[1], offsets[1] + learn_more_text.size()),
-      link_style);
+      views::StyledLabel::RangeStyleInfo::CreateForLink());
 
   // Layout the components.
   views::GridLayout* dialog_layout = new views::GridLayout(this);
diff --git a/chrome/browser/ui/views/tab_contents/chrome_web_contents_view_delegate_views.cc b/chrome/browser/ui/views/tab_contents/chrome_web_contents_view_delegate_views.cc
index c5f1eaa..bd4df7a 100644
--- a/chrome/browser/ui/views/tab_contents/chrome_web_contents_view_delegate_views.cc
+++ b/chrome/browser/ui/views/tab_contents/chrome_web_contents_view_delegate_views.cc
@@ -178,11 +178,8 @@
 }
 
 views::Widget* ChromeWebContentsViewDelegateViews::GetTopLevelWidget() {
-  gfx::NativeWindow top_level_window =
-      web_contents_->GetView()->GetTopLevelNativeWindow();
-  if (!top_level_window)
-    return NULL;
-  return views::Widget::GetWidgetForNativeWindow(top_level_window);
+  return views::Widget::GetTopLevelWidgetForNativeView(
+      web_contents_->GetView()->GetNativeView());
 }
 
 views::FocusManager*
diff --git a/chrome/browser/ui/views/tab_modal_confirm_dialog_views.cc b/chrome/browser/ui/views/tab_modal_confirm_dialog_views.cc
index 6823d1a..b6e35ab 100644
--- a/chrome/browser/ui/views/tab_modal_confirm_dialog_views.cc
+++ b/chrome/browser/ui/views/tab_modal_confirm_dialog_views.cc
@@ -39,7 +39,8 @@
 TabModalConfirmDialogViews::TabModalConfirmDialogViews(
     TabModalConfirmDialogDelegate* delegate,
     content::WebContents* web_contents)
-    : delegate_(delegate),
+    : web_contents_(web_contents),
+      delegate_(delegate),
       dialog_(NULL),
       browser_context_(web_contents->GetBrowserContext()) {
   views::MessageBoxView::InitParams init_params(delegate->GetMessage());
@@ -59,7 +60,7 @@
       web_contents_modal_dialog_manager->delegate()->
           GetWebContentsModalDialogHost());
   web_contents_modal_dialog_manager->ShowDialog(dialog_->GetNativeView());
-  delegate_->set_close_delegate(this);
+  delegate_->set_operations_delegate(this);
 }
 
 TabModalConfirmDialogViews::~TabModalConfirmDialogViews() {
@@ -77,6 +78,13 @@
   dialog_->Close();
 }
 
+void TabModalConfirmDialogViews::SetPreventCloseOnLoadStart(bool prevent) {
+  WebContentsModalDialogManager* web_contents_modal_dialog_manager =
+      WebContentsModalDialogManager::FromWebContents(web_contents_);
+  web_contents_modal_dialog_manager->SetPreventCloseOnLoadStart(
+      dialog_->GetNativeView(), prevent);
+}
+
 //////////////////////////////////////////////////////////////////////////////
 // TabModalConfirmDialogViews, views::LinkListener implementation:
 
diff --git a/chrome/browser/ui/views/tab_modal_confirm_dialog_views.h b/chrome/browser/ui/views/tab_modal_confirm_dialog_views.h
index 28d2e5b..36e3de3 100644
--- a/chrome/browser/ui/views/tab_modal_confirm_dialog_views.h
+++ b/chrome/browser/ui/views/tab_modal_confirm_dialog_views.h
@@ -58,10 +58,13 @@
 
   // TabModalConfirmDialogCloseDelegate:
   virtual void CloseDialog() OVERRIDE;
+  virtual void SetPreventCloseOnLoadStart(bool prevent) OVERRIDE;
 
   // views::LinkListener:
   virtual void LinkClicked(views::Link* source, int event_flags) OVERRIDE;
 
+  content::WebContents* web_contents_;
+
   scoped_ptr<TabModalConfirmDialogDelegate> delegate_;
 
   // The message box view whose commands we handle.
diff --git a/chrome/browser/ui/website_settings/website_settings.cc b/chrome/browser/ui/website_settings/website_settings.cc
index c0c175c..e4d268a 100644
--- a/chrome/browser/ui/website_settings/website_settings.cc
+++ b/chrome/browser/ui/website_settings/website_settings.cc
@@ -24,7 +24,6 @@
 #include "chrome/browser/content_settings/host_content_settings_map.h"
 #include "chrome/browser/content_settings/local_shared_objects_container.h"
 #include "chrome/browser/history/history_service_factory.h"
-#include "chrome/browser/infobars/infobar_service.h"
 #include "chrome/browser/policy/profile_policy_connector.h"
 #include "chrome/browser/policy/profile_policy_connector_factory.h"
 #include "chrome/browser/profiles/profile.h"
@@ -136,6 +135,7 @@
     case CONTENT_SETTINGS_TYPE_POPUPS:
     case CONTENT_SETTINGS_TYPE_FULLSCREEN:
     case CONTENT_SETTINGS_TYPE_MOUSELOCK:
+    case CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS:
       primary_pattern = ContentSettingsPattern::FromURL(site_url_);
       secondary_pattern = ContentSettingsPattern::Wildcard();
       break;
diff --git a/chrome/browser/ui/website_settings/website_settings_infobar_delegate.cc b/chrome/browser/ui/website_settings/website_settings_infobar_delegate.cc
index 9c2ba16..f51f741 100644
--- a/chrome/browser/ui/website_settings/website_settings_infobar_delegate.cc
+++ b/chrome/browser/ui/website_settings/website_settings_infobar_delegate.cc
@@ -12,6 +12,7 @@
 #include "grit/theme_resources.h"
 #include "ui/base/l10n/l10n_util.h"
 
+
 // static
 void WebsiteSettingsInfoBarDelegate::Create(InfoBarService* infobar_service) {
   infobar_service->AddInfoBar(scoped_ptr<InfoBarDelegate>(
diff --git a/chrome/browser/ui/website_settings/website_settings_infobar_delegate.h b/chrome/browser/ui/website_settings/website_settings_infobar_delegate.h
index 6f6b3d9..19fffa0 100644
--- a/chrome/browser/ui/website_settings/website_settings_infobar_delegate.h
+++ b/chrome/browser/ui/website_settings/website_settings_infobar_delegate.h
@@ -16,7 +16,8 @@
 // the reload right from the infobar.
 class WebsiteSettingsInfoBarDelegate : public ConfirmInfoBarDelegate {
  public:
-  // Creates a website settings delegate and adds it to |infobar_service|.
+  // Creates a website settings infobar delegate and adds it to
+  // |infobar_service|.
   static void Create(InfoBarService* infobar_service);
 
  private:
diff --git a/chrome/browser/ui/webui/OWNERS b/chrome/browser/ui/webui/OWNERS
index 6df6124..dfafdfb 100644
--- a/chrome/browser/ui/webui/OWNERS
+++ b/chrome/browser/ui/webui/OWNERS
@@ -1,6 +1,7 @@
 arv@chromium.org
 bauerb@chromium.org
 dbeam@chromium.org
+dubroy@chromium.org
 estade@chromium.org
 jhawkins@chromium.org
 nkostylev@chromium.org
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 8a3959e..b73b847 100644
--- a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
+++ b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
@@ -46,6 +46,7 @@
 #include "chrome/browser/ui/webui/profiler_ui.h"
 #include "chrome/browser/ui/webui/quota_internals/quota_internals_ui.h"
 #include "chrome/browser/ui/webui/signin/profile_signin_confirmation_ui.h"
+#include "chrome/browser/ui/webui/signin/user_chooser_ui.h"
 #include "chrome/browser/ui/webui/signin_internals_ui.h"
 #include "chrome/browser/ui/webui/sync_internals_ui.h"
 #include "chrome/browser/ui/webui/translate_internals/translate_internals_ui.h"
@@ -391,6 +392,13 @@
     return &NewWebUI<keyboard::KeyboardUIController>;
 #endif
 
+#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID) && !defined(OS_IOS)
+  if (url.host() == chrome::kChromeUIUserChooserHost &&
+      CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kNewProfileManagement))
+    return &NewWebUI<UserChooserUI>;
+#endif
+
   if (url.host() == chrome::kChromeUIChromeURLsHost ||
       url.host() == chrome::kChromeUICreditsHost ||
       url.host() == chrome::kChromeUIDNSHost ||
diff --git a/chrome/browser/ui/webui/chromeos/login/network_state_informer.cc b/chrome/browser/ui/webui/chromeos/login/network_state_informer.cc
index bc6cf68..f090f56 100644
--- a/chrome/browser/ui/webui/chromeos/login/network_state_informer.cc
+++ b/chrome/browser/ui/webui/chromeos/login/network_state_informer.cc
@@ -7,6 +7,7 @@
 #include "base/bind.h"
 #include "base/logging.h"
 #include "base/message_loop/message_loop.h"
+#include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/chromeos/net/proxy_config_handler.h"
 #include "chrome/browser/prefs/proxy_config_dictionary.h"
@@ -216,9 +217,10 @@
 
 bool NetworkStateInformer::IsProxyConfigured(const NetworkState* network) {
   DCHECK(network);
-
-  scoped_ptr<ProxyConfigDictionary> proxy_dict(
-      proxy_config::GetProxyConfigForNetwork(*network));
+  onc::ONCSource onc_source = onc::ONC_SOURCE_NONE;
+  scoped_ptr<ProxyConfigDictionary> proxy_dict =
+      proxy_config::GetProxyConfigForNetwork(
+          NULL, g_browser_process->local_state(), *network, &onc_source);
   ProxyPrefs::ProxyMode mode;
   return (proxy_dict &&
           proxy_dict->GetMode(&mode) &&
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 f679ad7..adfeb11 100644
--- a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc
@@ -196,10 +196,14 @@
 }
 
 bool IsProxyError(NetworkStateInformer::State state,
-                  ErrorScreenActor::ErrorReason reason) {
+                  ErrorScreenActor::ErrorReason reason,
+                  net::Error frame_error) {
   return state == NetworkStateInformer::PROXY_AUTH_REQUIRED ||
       reason == ErrorScreenActor::ERROR_REASON_PROXY_AUTH_CANCELLED ||
-      reason == ErrorScreenActor::ERROR_REASON_PROXY_CONNECTION_FAILED;
+      reason == ErrorScreenActor::ERROR_REASON_PROXY_CONNECTION_FAILED ||
+      (reason == ErrorScreenActor::ERROR_REASON_FRAME_ERROR &&
+       (frame_error == net::ERR_PROXY_CONNECTION_FAILED ||
+        frame_error == net::ERR_TUNNEL_CONNECTION_FAILED));
 }
 
 bool IsSigninScreen(const OobeUI::Screen screen) {
@@ -337,8 +341,7 @@
       is_first_update_state_call_(true),
       offline_login_active_(false),
       last_network_state_(NetworkStateInformer::UNKNOWN),
-      has_pending_auth_ui_(false),
-      ignore_next_user_abort_frame_error_(false) {
+      has_pending_auth_ui_(false) {
   DCHECK(network_state_informer_.get());
   DCHECK(error_screen_actor_);
   network_state_informer_->AddObserver(this);
@@ -446,7 +449,6 @@
 }
 
 void SigninScreenHandler::Show(bool oobe_ui) {
-  TRACE_EVENT_ASYNC_BEGIN0("ui", "ShowLoginWebUI", this);
   CHECK(delegate_);
   oobe_ui_ = oobe_ui;
   if (!page_is_ready()) {
@@ -628,7 +630,8 @@
     ReloadGaiaScreen();
   }
 
-  if (reason == ErrorScreenActor::ERROR_REASON_FRAME_ERROR) {
+  if (reason == ErrorScreenActor::ERROR_REASON_FRAME_ERROR &&
+      !IsProxyError(state, reason, frame_error_)) {
     LOG(WARNING) << "Retry page load due to reason: "
                  << ErrorReasonString(reason);
     ReloadGaiaScreen();
@@ -649,7 +652,7 @@
       network_state_informer_->last_network_service_path();
   const std::string network_id = GetNetworkUniqueId(service_path);
   const bool is_under_captive_portal = IsUnderCaptivePortal(state, reason);
-  const bool is_proxy_error = IsProxyError(state, reason);
+  const bool is_proxy_error = IsProxyError(state, reason, frame_error_);
   const bool is_gaia_loading_timeout =
       (reason == ErrorScreenActor::ERROR_REASON_LOADING_TIMEOUT);
 
@@ -728,7 +731,6 @@
   }
   LOG(WARNING) << "Reload auth extension frame.";
   frame_state_ = FRAME_STATE_LOADING;
-  ignore_next_user_abort_frame_error_ = true;
   CallJS("login.GaiaSigninScreen.doReload");
 }
 
@@ -1014,11 +1016,19 @@
   // Allow locally managed user creation only if:
   // 1. Enterprise managed device > is allowed by policy.
   // 2. Consumer device > owner exists.
+  // 3. New users are allowed by owner.
+
+  CrosSettings* cros_settings = CrosSettings::Get();
+  bool allow_new_user = false;
+  cros_settings->GetBoolean(kAccountsPrefAllowNewUser, &allow_new_user);
+
   bool managed_users_allowed =
       UserManager::Get()->AreLocallyManagedUsersAllowed();
   bool managed_users_can_create = false;
-  if (managed_users_allowed)
-    managed_users_can_create = delegate_->GetUsers().size() > 0;
+  if (managed_users_allowed) {
+    managed_users_can_create =
+        (delegate_->GetUsers().size() > 0) && allow_new_user;
+  }
   params->SetBoolean("managedUsersEnabled", managed_users_allowed);
   params->SetBoolean("managedUsersCanCreate", managed_users_can_create);
 }
@@ -1069,7 +1079,6 @@
   params.SetString("gaiaUrl", gaia_url.spec());
 
   frame_state_ = FRAME_STATE_LOADING;
-  ignore_next_user_abort_frame_error_ = true;
   CallJS("login.GaiaSigninScreen.loadAuthExtension", params);
 }
 
@@ -1436,9 +1445,8 @@
 }
 
 void SigninScreenHandler::HandleLoginVisible(const std::string& source) {
-  TRACE_EVENT_ASYNC_END0("ui", "ShowLoginWebUI", this);
-  LOG(INFO) << "Login WebUI >> LoginVisible, source: " << source << ", "
-            << "webui_visible_: " << webui_visible_;
+  LOG(WARNING) << "Login WebUI >> loginVisible, src: " << source << ", "
+               << "webui_visible_: " << webui_visible_;
   if (!webui_visible_) {
     // There might be multiple messages from OOBE UI so send notifications after
     // the first one only.
@@ -1446,6 +1454,8 @@
         chrome::NOTIFICATION_LOGIN_WEBUI_VISIBLE,
         content::NotificationService::AllSources(),
         content::NotificationService::NoDetails());
+    TRACE_EVENT_ASYNC_END0(
+        "ui", "ShowLoginWebUI", LoginDisplayHostImpl::kShowLoginWebUIid);
   }
   webui_visible_ = true;
   if (preferences_changed_delayed_)
@@ -1503,26 +1513,20 @@
 }
 
 void SigninScreenHandler::HandleFrameLoadingCompleted(int status) {
-  frame_error_ = static_cast<net::Error>(-status);
-  if (frame_error_ == net::OK) {
+  const net::Error frame_error = static_cast<net::Error>(-status);
+  if (frame_error == net::ERR_ABORTED) {
+    LOG(WARNING) << "Ignore gaia frame error: " << frame_error;
+    return;
+  }
+  frame_error_ = frame_error;
+  if (frame_error == net::OK) {
     LOG(INFO) << "Gaia frame is loaded";
     frame_state_ = FRAME_STATE_LOADED;
   } else {
-    // Ignore net::ERR_ABORTED frame error once.
-    if (ignore_next_user_abort_frame_error_ &&
-        frame_error_ == net::ERR_ABORTED) {
-      LOG(WARNING) << "Ignore gaia frame error: "  << frame_error_;
-      ignore_next_user_abort_frame_error_ = false;
-      return;
-    }
-
     LOG(WARNING) << "Gaia frame error: "  << frame_error_;
     frame_state_ = FRAME_STATE_ERROR;
   }
 
-  // Frame load okay and other frame error clears the flag.
-  ignore_next_user_abort_frame_error_ = false;
-
   if (network_state_informer_->state() != NetworkStateInformer::ONLINE)
     return;
   if (frame_state_ == FRAME_STATE_LOADED) {
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 1c17b8c..aea2d03 100644
--- a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h
@@ -459,12 +459,6 @@
   // NOTIFICATION_AUTH_CANCELLED.
   bool has_pending_auth_ui_;
 
-  // Whether to ignore the next net::ERR_ABORTED frame error. ERR_ABORTED could
-  // be triggered when reloading gaia frame's src with a pending load.
-  // ReloadGaiaExtension() sets this flag to true to ignore potential
-  // ERR_ABORTED triggered from its reload request. See http://crbug.com/242527.
-  bool ignore_next_user_abort_frame_error_;
-
   DISALLOW_COPY_AND_ASSIGN(SigninScreenHandler);
 };
 
diff --git a/chrome/browser/ui/webui/crashes_ui.cc b/chrome/browser/ui/webui/crashes_ui.cc
index b885b01..293cae7 100644
--- a/chrome/browser/ui/webui/crashes_ui.cc
+++ b/chrome/browser/ui/webui/crashes_ui.cc
@@ -19,6 +19,7 @@
 #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/web_contents.h"
 #include "content/public/browser/web_ui.h"
 #include "content/public/browser/web_ui_data_source.h"
@@ -104,7 +105,8 @@
 }
 
 void CrashesDOMHandler::RegisterMessages() {
-  upload_list_->LoadUploadListAsynchronously();
+  upload_list_->LoadUploadListAsynchronously(
+      content::BrowserThread::GetBlockingPool());
 
   web_ui()->RegisterMessageCallback("requestCrashList",
       base::Bind(&CrashesDOMHandler::HandleRequestCrashes,
diff --git a/chrome/browser/ui/webui/extensions/extension_icon_source.cc b/chrome/browser/ui/webui/extensions/extension_icon_source.cc
index 5cd6ed6..a25f0e3 100644
--- a/chrome/browser/ui/webui/extensions/extension_icon_source.cc
+++ b/chrome/browser/ui/webui/extensions/extension_icon_source.cc
@@ -65,7 +65,7 @@
 
 struct ExtensionIconSource::ExtensionIconRequest {
   content::URLDataSource::GotDataCallback callback;
-  const extensions::Extension* extension;
+  scoped_refptr<const extensions::Extension> extension;
   bool grayscale;
   int size;
   ExtensionIconSet::MatchType match;
diff --git a/chrome/browser/ui/webui/flash_ui.cc b/chrome/browser/ui/webui/flash_ui.cc
index 84a5eba..050b033 100644
--- a/chrome/browser/ui/webui/flash_ui.cc
+++ b/chrome/browser/ui/webui/flash_ui.cc
@@ -25,6 +25,7 @@
 #include "chrome/browser/ui/webui/crashes_ui.h"
 #include "chrome/common/chrome_version_info.h"
 #include "chrome/common/url_constants.h"
+#include "content/public/browser/browser_thread.h"
 #include "content/public/browser/gpu_data_manager.h"
 #include "content/public/browser/gpu_data_manager_observer.h"
 #include "content/public/browser/plugin_service.h"
@@ -33,6 +34,7 @@
 #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 "content/public/common/webplugininfo.h"
 #include "gpu/config/gpu_info.h"
 #include "grit/browser_resources.h"
 #include "grit/chromium_strings.h"
@@ -41,7 +43,6 @@
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "webkit/plugins/plugin_constants.h"
-#include "webkit/plugins/webplugininfo.h"
 
 #if defined(OS_WIN)
 #include "base/win/windows_version.h"
@@ -99,7 +100,7 @@
   void HandleRequestFlashInfo(const ListValue* args);
 
   // Callback for the Flash plugin information.
-  void OnGotPlugins(const std::vector<webkit::WebPluginInfo>& plugins);
+  void OnGotPlugins(const std::vector<content::WebPluginInfo>& plugins);
 
  private:
   // Called when we think we might have enough information to return data back
@@ -142,7 +143,8 @@
       has_plugin_info_(false) {
   // Request Crash data asynchronously.
   upload_list_ = CrashUploadList::Create(this);
-  upload_list_->LoadUploadListAsynchronously();
+  upload_list_->LoadUploadListAsynchronously(
+      content::BrowserThread::GetBlockingPool());
 
   // Watch for changes in GPUInfo.
   GpuDataManager::GetInstance()->AddObserver(this);
@@ -203,7 +205,7 @@
 }
 
 void FlashDOMHandler::OnGotPlugins(
-    const std::vector<webkit::WebPluginInfo>& plugins) {
+    const std::vector<content::WebPluginInfo>& plugins) {
   has_plugin_info_ = true;
   MaybeRespondToPage();
 }
@@ -266,7 +268,7 @@
   AddPair(list, l10n_util::GetStringUTF16(IDS_ABOUT_VERSION_OS), os_label);
 
   // Obtain the version of the Flash plugins.
-  std::vector<webkit::WebPluginInfo> info_array;
+  std::vector<content::WebPluginInfo> info_array;
   PluginService::GetInstance()->GetPluginInfoArray(
       GURL(), kFlashPluginSwfMimeType, false, &info_array, NULL);
   if (info_array.empty()) {
diff --git a/chrome/browser/ui/webui/gesture_config_ui.h b/chrome/browser/ui/webui/gesture_config_ui.h
index 3ef29cd..cfb8858 100644
--- a/chrome/browser/ui/webui/gesture_config_ui.h
+++ b/chrome/browser/ui/webui/gesture_config_ui.h
@@ -19,6 +19,9 @@
   virtual ~GestureConfigUI();
 
  private:
+  // TODO(mohsen): Add a whitelist of preferences that are allowed to be set or
+  // get here and check requested preferences against this whitelist.
+
   /**
    * Request a preference setting's value.
    * This method is asynchronous; the result is provided by a call to
diff --git a/chrome/browser/ui/webui/media/webrtc_logs_ui.cc b/chrome/browser/ui/webui/media/webrtc_logs_ui.cc
index 54de606..6d4505a 100644
--- a/chrome/browser/ui/webui/media/webrtc_logs_ui.cc
+++ b/chrome/browser/ui/webui/media/webrtc_logs_ui.cc
@@ -19,6 +19,7 @@
 #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/web_contents.h"
 #include "content/public/browser/web_ui.h"
 #include "content/public/browser/web_ui_data_source.h"
@@ -112,7 +113,8 @@
 }
 
 void WebRtcLogsDOMHandler::RegisterMessages() {
-  upload_list_->LoadUploadListAsynchronously();
+  upload_list_->LoadUploadListAsynchronously(
+      content::BrowserThread::GetBlockingPool());
 
   web_ui()->RegisterMessageCallback("requestWebRtcLogsList",
       base::Bind(&WebRtcLogsDOMHandler::HandleRequestWebRtcLogs,
diff --git a/chrome/browser/ui/webui/nacl_ui.cc b/chrome/browser/ui/webui/nacl_ui.cc
index 744d9cf..ed94181 100644
--- a/chrome/browser/ui/webui/nacl_ui.cc
+++ b/chrome/browser/ui/webui/nacl_ui.cc
@@ -28,13 +28,13 @@
 #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 "content/public/common/webplugininfo.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"
-#include "webkit/plugins/webplugininfo.h"
 
 #if defined(OS_WIN)
 #include "base/win/windows_version.h"
@@ -109,7 +109,7 @@
   void HandleRequestNaClInfo(const ListValue* args);
 
   // Callback for the NaCl plugin information.
-  void OnGotPlugins(const std::vector<webkit::WebPluginInfo>& plugins);
+  void OnGotPlugins(const std::vector<content::WebPluginInfo>& plugins);
 
   // A helper callback that receives the result of checking if PNaCl path
   // exists. |is_valid| is true if the PNaCl path that was returned by
@@ -236,7 +236,7 @@
 }
 
 void NaClDomHandler::OnGotPlugins(
-    const std::vector<webkit::WebPluginInfo>& plugins) {
+    const std::vector<content::WebPluginInfo>& plugins) {
   has_plugin_info_ = true;
   MaybeRespondToPage();
 }
@@ -282,7 +282,7 @@
   AddLineBreak(list.get());
 
   // Obtain the version of the NaCl plugin.
-  std::vector<webkit::WebPluginInfo> info_array;
+  std::vector<content::WebPluginInfo> info_array;
   PluginService::GetInstance()->GetPluginInfoArray(
       GURL(), "application/x-nacl", false, &info_array, NULL);
   string16 nacl_version;
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 1c5a136..e896dfa 100644
--- a/chrome/browser/ui/webui/net_internals/net_internals_ui.cc
+++ b/chrome/browser/ui/webui/net_internals/net_internals_ui.cc
@@ -1555,20 +1555,12 @@
     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)) {
+  if (!certificate_handler.ImportCertificates(certificates, onc_source, NULL)) {
     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::NetworkLibrary::Get();
   network_library->LoadOncNetworks(network_configs, onc_source);
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 aacd04b..cffe88f 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
@@ -88,7 +88,7 @@
   net::URLRequestContext* context = context_getter->GetURLRequestContext();
   net::HttpNetworkSession* http_network_session =
       context->http_transaction_factory()->GetSession();
-  net::HttpServerProperties* http_server_properties =
+  base::WeakPtr<net::HttpServerProperties> http_server_properties =
       http_network_session->http_server_properties();
   net::HostPortPair origin(hostname, port);
   http_server_properties->SetPipelineCapability(origin, capability);
diff --git a/chrome/browser/ui/webui/ntp/android/navigation_handler.cc b/chrome/browser/ui/webui/ntp/android/navigation_handler.cc
new file mode 100644
index 0000000..d5c9a2e
--- /dev/null
+++ b/chrome/browser/ui/webui/ntp/android/navigation_handler.cc
@@ -0,0 +1,89 @@
+// Copyright 2013 The Chromium Authors. 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/ntp/android/navigation_handler.h"
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "base/metrics/histogram.h"
+#include "base/values.h"
+#include "chrome/browser/google/google_util.h"
+#include "chrome/common/url_constants.h"
+#include "content/public/browser/navigation_entry.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_ui.h"
+#include "content/public/common/page_transition_types.h"
+
+NavigationHandler::NavigationHandler() {}
+
+NavigationHandler::~NavigationHandler() {
+  // Record an omnibox-based navigation, if there is one.
+  content::NavigationEntry* entry =
+      web_ui()->GetWebContents()->GetController().GetActiveEntry();
+  if (!entry)
+    return;
+
+  if (!(entry->GetTransitionType() &
+        content::PAGE_TRANSITION_FROM_ADDRESS_BAR) ||
+      entry->GetTransitionType() & content::PAGE_TRANSITION_FORWARD_BACK) {
+    return;
+  }
+
+  if (entry->GetURL().SchemeIs(chrome::kChromeUIScheme) &&
+      entry->GetURL().host() == chrome::kChromeUINewTabHost) {
+    return;
+  }
+
+  Action action;
+  if ((entry->GetTransitionType() & content::PAGE_TRANSITION_CORE_MASK) ==
+      content::PAGE_TRANSITION_GENERATED) {
+    action = ACTION_SEARCHED_USING_OMNIBOX;
+  } else if (google_util::IsGoogleHomePageUrl(entry->GetURL())) {
+    action = ACTION_NAVIGATED_TO_GOOGLE_HOMEPAGE;
+  } else {
+    action = ACTION_NAVIGATED_USING_OMNIBOX;
+  }
+  RecordAction(action);
+}
+
+void NavigationHandler::RegisterMessages() {
+  web_ui()->RegisterMessageCallback(
+      "openedMostVisited",
+      base::Bind(&NavigationHandler::HandleOpenedMostVisited,
+                 base::Unretained(this)));
+  web_ui()->RegisterMessageCallback(
+      "openedRecentlyClosed",
+      base::Bind(&NavigationHandler::HandleOpenedRecentlyClosed,
+                 base::Unretained(this)));
+  web_ui()->RegisterMessageCallback(
+      "openedBookmark",
+      base::Bind(&NavigationHandler::HandleOpenedBookmark,
+                 base::Unretained(this)));
+  web_ui()->RegisterMessageCallback(
+      "openedForeignSession",
+      base::Bind(&NavigationHandler::HandleOpenedForeignSession,
+                 base::Unretained(this)));
+}
+
+void NavigationHandler::HandleOpenedMostVisited(const base::ListValue* args) {
+  RecordAction(ACTION_OPENED_MOST_VISITED_ENTRY);
+}
+
+void NavigationHandler::HandleOpenedRecentlyClosed(
+    const base::ListValue* args) {
+  RecordAction(ACTION_OPENED_RECENTLY_CLOSED_ENTRY);
+}
+
+void NavigationHandler::HandleOpenedBookmark(const base::ListValue* args) {
+  RecordAction(ACTION_OPENED_BOOKMARK);
+}
+
+void NavigationHandler::HandleOpenedForeignSession(
+    const base::ListValue* args) {
+  RecordAction(ACTION_OPENED_FOREIGN_SESSION);
+}
+
+void NavigationHandler::RecordAction(Action action) {
+  UMA_HISTOGRAM_ENUMERATION("NewTabPage.ActionAndroid", action, NUM_ACTIONS);
+}
diff --git a/chrome/browser/ui/webui/ntp/android/navigation_handler.h b/chrome/browser/ui/webui/ntp/android/navigation_handler.h
new file mode 100644
index 0000000..fc45d86
--- /dev/null
+++ b/chrome/browser/ui/webui/ntp/android/navigation_handler.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_UI_WEBUI_NTP_ANDROID_NAVIGATION_HANDLER_H_
+#define CHROME_BROWSER_UI_WEBUI_NTP_ANDROID_NAVIGATION_HANDLER_H_
+
+#include "base/compiler_specific.h"
+#include "content/public/browser/web_ui_message_handler.h"
+
+namespace base {
+class ListValue;
+}
+
+// Records a UMA stat ("NewTabPage.ActionAndroid") for the action the user takes
+// to navigate away from the NTP.
+class NavigationHandler : public content::WebUIMessageHandler {
+ public:
+  NavigationHandler();
+  virtual ~NavigationHandler();
+
+  // WebUIMessageHandler implementation.
+  virtual void RegisterMessages() OVERRIDE;
+
+  // Callback for "openedMostVisited".
+  void HandleOpenedMostVisited(const base::ListValue* args);
+
+  // Callback for "openedRecentlyClosed".
+  void HandleOpenedRecentlyClosed(const base::ListValue* args);
+
+  // Callback for "openedBookmark".
+  void HandleOpenedBookmark(const base::ListValue* args);
+
+  // Callback for "openedForeignSession".
+  void HandleOpenedForeignSession(const base::ListValue* args);
+
+ private:
+  // Possible actions taken by the user on the NTP. This enum is also defined in
+  // histograms.xml. WARNING: these values must stay in sync with histograms.xml
+  // and new actions can be added only at the end of the enum.
+  enum Action {
+    // User performed a search using the omnibox
+    ACTION_SEARCHED_USING_OMNIBOX = 0,
+    // User navigated to Google search homepage using the omnibox
+    ACTION_NAVIGATED_TO_GOOGLE_HOMEPAGE = 1,
+    // User navigated to any other page using the omnibox
+    ACTION_NAVIGATED_USING_OMNIBOX = 2,
+    // User opened a most visited page
+    ACTION_OPENED_MOST_VISITED_ENTRY = 3,
+    // User opened a recently closed tab
+    ACTION_OPENED_RECENTLY_CLOSED_ENTRY = 4,
+    // User opened a bookmark
+    ACTION_OPENED_BOOKMARK = 5,
+    // User opened a foreign session (from other devices section)
+    ACTION_OPENED_FOREIGN_SESSION = 6,
+    // The number of possible actions
+    NUM_ACTIONS = 7
+  };
+
+  void RecordAction(Action action);
+
+  DISALLOW_COPY_AND_ASSIGN(NavigationHandler);
+};
+
+#endif  // CHROME_BROWSER_UI_WEBUI_NTP_ANDROID_NAVIGATION_HANDLER_H_
diff --git a/chrome/browser/ui/webui/ntp/new_tab_ui.cc b/chrome/browser/ui/webui/ntp/new_tab_ui.cc
index 35ac6b5..0d4836a 100644
--- a/chrome/browser/ui/webui/ntp/new_tab_ui.cc
+++ b/chrome/browser/ui/webui/ntp/new_tab_ui.cc
@@ -45,6 +45,7 @@
 #else
 #include "chrome/browser/ui/webui/ntp/android/bookmarks_handler.h"
 #include "chrome/browser/ui/webui/ntp/android/context_menu_handler.h"
+#include "chrome/browser/ui/webui/ntp/android/navigation_handler.h"
 #include "chrome/browser/ui/webui/ntp/android/new_tab_page_ready_handler.h"
 #include "chrome/browser/ui/webui/ntp/android/promo_handler.h"
 #endif
@@ -104,8 +105,8 @@
     web_ui->AddMessageHandler(new browser_sync::ForeignSessionHandler());
     web_ui->AddMessageHandler(new MostVisitedHandler());
     web_ui->AddMessageHandler(new RecentlyClosedTabsHandler());
-    web_ui->AddMessageHandler(new MetricsHandler());
 #if !defined(OS_ANDROID)
+    web_ui->AddMessageHandler(new MetricsHandler());
     web_ui->AddMessageHandler(new NewTabPageHandler());
     if (NewTabUI::IsDiscoveryInNTPEnabled())
       web_ui->AddMessageHandler(new SuggestionsHandler());
@@ -128,6 +129,7 @@
   // These handlers are specific to the Android NTP page.
   web_ui->AddMessageHandler(new BookmarksHandler());
   web_ui->AddMessageHandler(new ContextMenuHandler());
+  web_ui->AddMessageHandler(new NavigationHandler());
   web_ui->AddMessageHandler(new NewTabPageReadyHandler());
   if (!GetProfile()->IsOffTheRecord())
     web_ui->AddMessageHandler(new PromoHandler());
diff --git a/chrome/browser/ui/webui/omnibox/omnibox_ui_handler.cc b/chrome/browser/ui/webui/omnibox/omnibox_ui_handler.cc
index 3b62f03..c436f9d 100644
--- a/chrome/browser/ui/webui/omnibox/omnibox_ui_handler.cc
+++ b/chrome/browser/ui/webui/omnibox/omnibox_ui_handler.cc
@@ -123,8 +123,8 @@
     output->SetInteger(item_prefix + ".relevance", it->relevance);
     output->SetBoolean(item_prefix + ".deletable", it->deletable);
     output->SetString(item_prefix + ".fill_into_edit", it->fill_into_edit);
-    output->SetInteger(item_prefix + ".inline_autocomplete_offset",
-                       it->inline_autocomplete_offset);
+    output->SetString(item_prefix + ".inline_autocompletion",
+                       it->inline_autocompletion);
     output->SetString(item_prefix + ".destination_url",
                       it->destination_url.spec());
     output->SetString(item_prefix + ".contents", it->contents);
diff --git a/chrome/browser/ui/webui/options/browser_options_handler.h b/chrome/browser/ui/webui/options/browser_options_handler.h
index a9173f8..06199f0 100644
--- a/chrome/browser/ui/webui/options/browser_options_handler.h
+++ b/chrome/browser/ui/webui/options/browser_options_handler.h
@@ -10,6 +10,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
+#include "base/prefs/pref_change_registrar.h"
 #include "base/prefs/pref_member.h"
 #include "base/time/time.h"
 #include "chrome/browser/profiles/profile.h"
@@ -24,8 +25,6 @@
 
 #if defined(OS_CHROMEOS)
 #include "chrome/browser/chromeos/system/pointer_device_observer.h"
-#else
-#include "base/prefs/pref_change_registrar.h"
 #endif  // defined(OS_CHROMEOS)
 
 class AutocompleteController;
diff --git a/chrome/browser/ui/webui/options/chromeos/core_chromeos_options_handler.cc b/chrome/browser/ui/webui/options/chromeos/core_chromeos_options_handler.cc
index e946409..7ef79d1 100644
--- a/chrome/browser/ui/webui/options/chromeos/core_chromeos_options_handler.cc
+++ b/chrome/browser/ui/webui/options/chromeos/core_chromeos_options_handler.cc
@@ -104,20 +104,24 @@
 }
 
 void CoreChromeOSOptionsHandler::InitializeHandler() {
-  // In case the options page is reloaded, forget the last selected network.
+  // This function is both called on the initial page load and on each reload.
+  // For the latter case, forget the last selected network.
   proxy_config_service_.SetCurrentNetwork(std::string());
+  // And clear the cached configuration.
+  proxy_config_service_.UpdateFromPrefs();
 
   CoreOptionsHandler::InitializeHandler();
 
+  PrefService* profile_prefs = NULL;
   Profile* profile = Profile::FromWebUI(web_ui());
-  PrefService* prefs = profile->GetPrefs();
-  proxy_prefs_.Init(prefs);
-  proxy_prefs_.Add(prefs::kProxy,
-                   base::Bind(&CoreChromeOSOptionsHandler::OnPreferenceChanged,
-                              base::Unretained(this),
-                              prefs));
-  proxy_config_service_.SetPrefs(ProfileHelper::IsSigninProfile(profile),
-                                 prefs);
+  if (!ProfileHelper::IsSigninProfile(profile)) {
+    profile_prefs = profile->GetPrefs();
+    ObservePref(prefs::kOpenNetworkConfiguration);
+  }
+  ObservePref(prefs::kProxy);
+  ObservePref(prefs::kDeviceOpenNetworkConfiguration);
+  proxy_config_service_.SetPrefs(profile_prefs,
+                                 g_browser_process->local_state());
 }
 
 base::Value* CoreChromeOSOptionsHandler::FetchPref(
@@ -215,12 +219,6 @@
   ::options::CoreOptionsHandler::Observe(type, source, details);
 }
 
-void CoreChromeOSOptionsHandler::SelectNetwork(
-    const std::string& service_path) {
-  proxy_config_service_.SetCurrentNetwork(service_path);
-  NotifyProxyPrefsChanged();
-}
-
 void CoreChromeOSOptionsHandler::SelectNetworkCallback(
     const base::ListValue* args) {
   std::string service_path;
@@ -229,18 +227,24 @@
     NOTREACHED();
     return;
   }
-  SelectNetwork(service_path);
+  proxy_config_service_.SetCurrentNetwork(service_path);
+  NotifyProxyPrefsChanged();
 }
 
 void CoreChromeOSOptionsHandler::OnPreferenceChanged(
     PrefService* service,
     const std::string& pref_name) {
-  // Special handling for preferences kUseSharedProxies and kProxy, the latter
-  // controls the former and decides if it's managed by policy/extension.
-  const PrefService* pref_service = Profile::FromWebUI(web_ui())->GetPrefs();
-  if (service == pref_service &&
-      (proxy_prefs_.IsObserved(pref_name) ||
-       pref_name == prefs::kUseSharedProxies)) {
+  // Redetermine the current proxy settings and notify the UI if any of these
+  // preferences change.
+  if (pref_name == prefs::kOpenNetworkConfiguration ||
+      pref_name == prefs::kDeviceOpenNetworkConfiguration ||
+      pref_name == prefs::kProxy) {
+    NotifyProxyPrefsChanged();
+    return;
+  }
+  if (pref_name == prefs::kUseSharedProxies) {
+    // kProxy controls kUseSharedProxies and decides if it's managed by
+    // policy/extension.
     NotifyPrefChanged(prefs::kUseSharedProxies, prefs::kProxy);
     return;
   }
@@ -257,6 +261,7 @@
 }
 
 void CoreChromeOSOptionsHandler::NotifyProxyPrefsChanged() {
+  proxy_config_service_.UpdateFromPrefs();
   for (size_t i = 0; i < kProxySettingsCount; ++i) {
     base::Value* value = NULL;
     proxy_cros_settings_parser::GetProxyPrefValue(
diff --git a/chrome/browser/ui/webui/options/chromeos/core_chromeos_options_handler.h b/chrome/browser/ui/webui/options/chromeos/core_chromeos_options_handler.h
index 52cb431..d73db1b 100644
--- a/chrome/browser/ui/webui/options/chromeos/core_chromeos_options_handler.h
+++ b/chrome/browser/ui/webui/options/chromeos/core_chromeos_options_handler.h
@@ -6,7 +6,6 @@
 #define CHROME_BROWSER_UI_WEBUI_OPTIONS_CHROMEOS_CORE_CHROMEOS_OPTIONS_HANDLER_H_
 
 #include "base/compiler_specific.h"
-#include "base/prefs/pref_change_registrar.h"
 #include "chrome/browser/chromeos/ui_proxy_config_service.h"
 #include "chrome/browser/ui/webui/options/core_options_handler.h"
 
@@ -38,10 +37,6 @@
                        const content::NotificationSource& source,
                        const content::NotificationDetails& details) OVERRIDE;
 
-  // Select the network to show proxy settings for. Triggers pref notifications
-  // about the updated proxy settings.
-  void SelectNetwork(const std::string& service_path);
-
  private:
   virtual void OnPreferenceChanged(PrefService* service,
                                    const std::string& pref_name) OVERRIDE;
@@ -55,7 +50,6 @@
   void NotifyProxyPrefsChanged();
 
   UIProxyConfigService proxy_config_service_;
-  PrefChangeRegistrar proxy_prefs_;
 };
 
 }  // namespace options
diff --git a/chrome/browser/ui/webui/options/chromeos/cros_language_options_handler.cc b/chrome/browser/ui/webui/options/chromeos/cros_language_options_handler.cc
index 315738b..25fecc1 100644
--- a/chrome/browser/ui/webui/options/chromeos/cros_language_options_handler.cc
+++ b/chrome/browser/ui/webui/options/chromeos/cros_language_options_handler.cc
@@ -36,17 +36,8 @@
 // TODO(zork): Remove this blacklist when fonts are added to Chrome OS.
 // see: crbug.com/240586
 
-const char* kLanguageBlacklist[] = {
-  "km", // Khmer language
-  "si", // Sinhala language
-};
-
 bool IsBlacklisted(const std::string& language_code) {
-  for (size_t i = 0; i < arraysize(kLanguageBlacklist); ++i) {
-    if (language_code == kLanguageBlacklist[i])
-      return true;
-  }
-  return false;
+  return language_code == "si"; // Sinhala
 }
 
 } // namespace
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 9d1f9e1..9dad157 100644
--- a/chrome/browser/ui/webui/options/chromeos/display_options_handler.cc
+++ b/chrome/browser/ui/webui/options/chromeos/display_options_handler.cc
@@ -146,7 +146,7 @@
 void DisplayOptionsHandler::SendAllDisplayInfo() {
   DisplayManager* display_manager = GetDisplayManager();
 
-  std::vector<const gfx::Display*> displays;
+  std::vector<gfx::Display> displays;
   for (size_t i = 0; i < display_manager->GetNumDisplays(); ++i) {
     displays.push_back(display_manager->GetDisplayAt(i));
   }
@@ -154,7 +154,7 @@
 }
 
 void DisplayOptionsHandler::SendDisplayInfo(
-    const std::vector<const gfx::Display*> displays) {
+    const std::vector<gfx::Display>& displays) {
   DisplayManager* display_manager = GetDisplayManager();
   ash::DisplayController* display_controller =
       ash::Shell::GetInstance()->display_controller();
@@ -163,27 +163,27 @@
   int64 primary_id = ash::Shell::GetScreen()->GetPrimaryDisplay().id();
   base::ListValue js_displays;
   for (size_t i = 0; i < displays.size(); ++i) {
-    const gfx::Display* display = displays[i];
+    const gfx::Display& display = displays[i];
     const ash::internal::DisplayInfo& display_info =
-        display_manager->GetDisplayInfo(display->id());
-    const gfx::Rect& bounds = display->bounds();
+        display_manager->GetDisplayInfo(display.id());
+    const gfx::Rect& bounds = display.bounds();
     base::DictionaryValue* js_display = new base::DictionaryValue();
-    js_display->SetString("id", base::Int64ToString(display->id()));
+    js_display->SetString("id", base::Int64ToString(display.id()));
     js_display->SetInteger("x", bounds.x());
     js_display->SetInteger("y", bounds.y());
     js_display->SetInteger("width", bounds.width());
     js_display->SetInteger("height", bounds.height());
     js_display->SetString("name",
-                          display_manager->GetDisplayNameForId(display->id()));
-    js_display->SetBoolean("isPrimary", display->id() == primary_id);
-    js_display->SetBoolean("isInternal", display->IsInternal());
+                          display_manager->GetDisplayNameForId(display.id()));
+    js_display->SetBoolean("isPrimary", display.id() == primary_id);
+    js_display->SetBoolean("isInternal", display.IsInternal());
     js_display->SetInteger("orientation",
                            static_cast<int>(display_info.rotation()));
     std::vector<float> ui_scales = DisplayManager::GetScalesForDisplay(
         display_info);
     base::ListValue* js_scales = new base::ListValue();
     gfx::SizeF base_size = display_info.bounds_in_pixel().size();
-    base_size.Scale(1.0f / display->device_scale_factor());
+    base_size.Scale(1.0f / display.device_scale_factor());
     if (display_info.rotation() == gfx::Display::ROTATE_90 ||
         display_info.rotation() == gfx::Display::ROTATE_270) {
       float tmp = base_size.width();
diff --git a/chrome/browser/ui/webui/options/chromeos/display_options_handler.h b/chrome/browser/ui/webui/options/chromeos/display_options_handler.h
index 2459ac9..e34617b 100644
--- a/chrome/browser/ui/webui/options/chromeos/display_options_handler.h
+++ b/chrome/browser/ui/webui/options/chromeos/display_options_handler.h
@@ -42,7 +42,7 @@
   void SendAllDisplayInfo();
 
   // Sends the specified display information to the web_ui of options page.
-  void SendDisplayInfo(const std::vector<const gfx::Display*> displays);
+  void SendDisplayInfo(const std::vector<gfx::Display>& displays);
 
   // Called when the fade-out animation for mirroring status change is finished.
   void OnFadeOutForMirroringFinished(bool is_mirroring);
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 e9718a8..39b6d61 100644
--- a/chrome/browser/ui/webui/options/chromeos/internet_options_handler.cc
+++ b/chrome/browser/ui/webui/options/chromeos/internet_options_handler.cc
@@ -279,6 +279,13 @@
       base::Bind(&ShillError, "SetNetworkProperty"));
 }
 
+const base::DictionaryValue* FindPolicyForActiveUser(
+    const NetworkState* network,
+    onc::ONCSource* onc_source) {
+  *onc_source = network->onc_source();
+  return NetworkLibrary::Get()->FindOncForNetwork(network->guid());
+}
+
 std::string ActivationStateString(const std::string& activation_state) {
   int id;
   if (activation_state == flimflam::kActivationStateActivated)
@@ -636,12 +643,13 @@
     shill_properties.GetString(flimflam::kL2tpIpsecUserProperty, &username);
   dictionary->SetString(kTagUsername, username);
 
-  // TODO(stevenjb): Move FindOncFornetwork()
-  const base::DictionaryValue* onc = NetworkLibrary::Get()->
-      FindOncForNetwork(vpn->guid());
+  onc::ONCSource onc_source = onc::ONC_SOURCE_NONE;
+  const base::DictionaryValue* onc = FindPolicyForActiveUser(vpn, &onc_source);
+
   NetworkPropertyUIData hostname_ui_data;
   hostname_ui_data.ParseOncProperty(
-      vpn->onc_source(), onc,
+      onc_source,
+      onc,
       base::StringPrintf("%s.%s", onc::network_config::kVPN, onc::vpn::kHost));
   std::string provider_host;
   shill_properties.GetString(flimflam::kProviderHostProperty, &provider_host);
@@ -1422,9 +1430,10 @@
     return;
   }
 
-  const NetworkPropertyUIData property_ui_data(network->onc_source());
-  const base::DictionaryValue* onc = NetworkLibrary::Get()->
-      FindOncForNetwork(network->guid());
+  onc::ONCSource onc_source = onc::ONC_SOURCE_NONE;
+  const base::DictionaryValue* onc =
+      FindPolicyForActiveUser(network, &onc_source);
+  const NetworkPropertyUIData property_ui_data(onc_source);
 
   base::DictionaryValue dictionary;
 
@@ -1496,7 +1505,7 @@
                      new base::FundamentalValue(preferred),
                      property_ui_data);
 
-  NetworkPropertyUIData auto_connect_ui_data(network->onc_source());
+  NetworkPropertyUIData auto_connect_ui_data(onc_source);
   std::string onc_path_to_auto_connect;
   if (type == flimflam::kTypeWifi) {
     onc_path_to_auto_connect = base::StringPrintf(
@@ -1511,9 +1520,7 @@
   }
   if (!onc_path_to_auto_connect.empty()) {
     auto_connect_ui_data.ParseOncProperty(
-        network->onc_source(),
-        onc,
-        onc_path_to_auto_connect);
+        onc_source, onc, onc_path_to_auto_connect);
   }
   SetValueDictionary(&dictionary, kTagAutoConnect,
                      new base::FundamentalValue(network->auto_connect()),
diff --git a/chrome/browser/ui/webui/options/chromeos/timezone_options_util.cc b/chrome/browser/ui/webui/options/chromeos/timezone_options_util.cc
index c6cd40b..4d09319 100644
--- a/chrome/browser/ui/webui/options/chromeos/timezone_options_util.cc
+++ b/chrome/browser/ui/webui/options/chromeos/timezone_options_util.cc
@@ -15,10 +15,10 @@
 #include "base/values.h"
 #include "chrome/browser/chromeos/system/timezone_settings.h"
 #include "grit/generated_resources.h"
-#include "third_party/icu/public/common/unicode/ures.h"
-#include "third_party/icu/public/common/unicode/utypes.h"
-#include "third_party/icu/public/i18n/unicode/calendar.h"
-#include "third_party/icu/public/i18n/unicode/timezone.h"
+#include "third_party/icu/source/common/unicode/ures.h"
+#include "third_party/icu/source/common/unicode/utypes.h"
+#include "third_party/icu/source/i18n/unicode/calendar.h"
+#include "third_party/icu/source/i18n/unicode/timezone.h"
 #include "ui/base/l10n/l10n_util.h"
 
 namespace {
diff --git a/chrome/browser/ui/webui/options/core_options_handler.cc b/chrome/browser/ui/webui/options/core_options_handler.cc
index 5544b21..c933690 100644
--- a/chrome/browser/ui/webui/options/core_options_handler.cc
+++ b/chrome/browser/ui/webui/options/core_options_handler.cc
@@ -212,7 +212,11 @@
         base::Bind(&CoreOptionsHandler::OnPreferenceChanged,
                    base::Unretained(this),
                    local_state_registrar_.prefs()));
-  } else {
+  }
+  // TODO(pneubeck): change this to if/else once kProxy is only used as a user
+  // pref. Currently, it is both a user and a local state pref.
+  if (Profile::FromWebUI(web_ui())->GetPrefs()->FindPreference(
+          pref_name.c_str())) {
     registrar_.Add(
         pref_name.c_str(),
         base::Bind(&CoreOptionsHandler::OnPreferenceChanged,
diff --git a/chrome/browser/ui/webui/options/manage_profile_handler.cc b/chrome/browser/ui/webui/options/manage_profile_handler.cc
index 3bda4a6..d684067 100644
--- a/chrome/browser/ui/webui/options/manage_profile_handler.cc
+++ b/chrome/browser/ui/webui/options/manage_profile_handler.cc
@@ -333,7 +333,10 @@
       !base::GetValueAsFilePath(*file_path_value, &profile_file_path))
     return;
 
-  AppListService::Get()->SetAppListProfile(profile_file_path);
+  AppListService* app_list_service = AppListService::Get();
+  app_list_service->SetProfilePath(profile_file_path);
+  app_list_service->Show();
+
   // Close the settings app, since it will now be for the wrong profile.
   web_ui()->GetWebContents()->Close();
 }
diff --git a/chrome/browser/ui/webui/options/preferences_browsertest.cc b/chrome/browser/ui/webui/options/preferences_browsertest.cc
index 6735944..365e211 100644
--- a/chrome/browser/ui/webui/options/preferences_browsertest.cc
+++ b/chrome/browser/ui/webui/options/preferences_browsertest.cc
@@ -18,13 +18,13 @@
 #include "chrome/browser/policy/browser_policy_connector.h"
 #include "chrome/browser/policy/external_data_fetcher.h"
 #include "chrome/browser/policy/policy_map.h"
+#include "chrome/browser/policy/policy_types.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/pref_names.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/test/base/ui_test_utils.h"
-#include "components/user_prefs/user_prefs.h"
 #include "content/public/browser/notification_details.h"
 #include "content/public/browser/notification_source.h"
 #include "content/public/browser/render_view_host.h"
@@ -36,13 +36,19 @@
 
 #if defined(OS_CHROMEOS)
 #include "base/strings/stringprintf.h"
+#include "chrome/browser/browser_process.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"
 #include "chrome/browser/chromeos/settings/cros_settings_names.h"
 #include "chrome/browser/prefs/proxy_config_dictionary.h"
+#include "chromeos/dbus/dbus_thread_manager.h"
+#include "chromeos/dbus/shill_profile_client.h"
+#include "chromeos/dbus/shill_service_client.h"
 #include "chromeos/network/network_state.h"
 #include "chromeos/network/network_state_handler.h"
+#include "content/public/test/test_utils.h"
+#include "third_party/cros_system_api/dbus/service_constants.h"
 #endif
 
 using testing::AllOf;
@@ -93,8 +99,8 @@
   ASSERT_TRUE(web_contents);
   render_view_host_ = web_contents->GetRenderViewHost();
   ASSERT_TRUE(render_view_host_);
-  pref_change_registrar_.Init(user_prefs::UserPrefs::Get(browser()->profile()));
   pref_service_ = browser()->profile()->GetPrefs();
+  pref_change_registrar_.Init(pref_service_);
   ASSERT_TRUE(content::ExecuteScript(render_view_host_,
       "function TestEnv() {"
       "  this.sentinelName_ = 'download.prompt_for_download';"
@@ -180,8 +186,8 @@
   OnCommit(pref_service_->FindPreference(pref_name.c_str()));
 }
 
-// Sets up a mock user policy provider.
 void PreferencesBrowserTest::SetUpInProcessBrowserTestFixture() {
+  // Sets up a mock policy provider for user and device policies.
   EXPECT_CALL(policy_provider_, IsInitializationComplete(_))
       .WillRepeatedly(Return(true));
   EXPECT_CALL(policy_provider_, RegisterPolicyDomain(_))
@@ -712,19 +718,26 @@
   STLDeleteElements(&decorated_non_default_values);
 }
 
+namespace {
+
+const char* kUserProfilePath = "user_profile";
+
+}  // namespace
+
 class ProxyPreferencesBrowserTest : public PreferencesBrowserTest {
  public:
   virtual void SetUpOnMainThread() OVERRIDE {
+    SetupNetworkEnvironment();
+    content::RunAllPendingInMessageLoop();
+
     scoped_ptr<base::DictionaryValue> proxy_config_dict(
-        ProxyConfigDictionary::CreateFixedServers(
-            "127.0.0.1:8080",
-            "*.google.com, 1.2.3.4:22"));
+        ProxyConfigDictionary::CreateFixedServers("127.0.0.1:8080",
+                                                  "*.google.com, 1.2.3.4:22"));
 
     ProxyConfigDictionary proxy_config(proxy_config_dict.get());
 
     const chromeos::NetworkState* network = GetDefaultNetwork();
-    chromeos::proxy_config::SetProxyConfigForNetwork(
-        proxy_config, *network);
+    chromeos::proxy_config::SetProxyConfigForNetwork(proxy_config, *network);
 
     std::string url = base::StringPrintf("%s?network=%s",
                                          chrome::kChromeUIProxySettingsURL,
@@ -735,9 +748,62 @@
   }
 
  protected:
+  void SetupNetworkEnvironment() {
+    chromeos::ShillProfileClient::TestInterface* profile_test =
+        chromeos::DBusThreadManager::Get()->GetShillProfileClient()
+            ->GetTestInterface();
+    chromeos::ShillServiceClient::TestInterface* service_test =
+        chromeos::DBusThreadManager::Get()->GetShillServiceClient()
+            ->GetTestInterface();
+
+    profile_test->AddProfile(kUserProfilePath, "user");
+
+    service_test->ClearServices();
+    service_test->AddService("stub_ethernet",
+                             "eth0",
+                             flimflam::kTypeEthernet,
+                             flimflam::kStateOnline,
+                             true,   // add to visible
+                             true);  // add to watchlist
+    service_test->SetServiceProperty("stub_ethernet",
+                                     flimflam::kGuidProperty,
+                                     base::StringValue("stub_ethernet"));
+    service_test->SetServiceProperty("stub_ethernet",
+                                     flimflam::kProfileProperty,
+                                     base::StringValue(kUserProfilePath));
+    profile_test->AddService(kUserProfilePath, "stub_wifi2");
+  }
+
+  void SetONCPolicy(const char* policy_name, policy::PolicyScope scope) {
+    std::string onc_policy =
+        "{ \"NetworkConfigurations\": ["
+        "    { \"GUID\": \"stub_ethernet\","
+        "      \"Type\": \"Ethernet\","
+        "      \"Name\": \"My Ethernet\","
+        "      \"Ethernet\": {"
+        "        \"Authentication\": \"None\" },"
+        "      \"ProxySettings\": {"
+        "        \"PAC\": \"http://domain.com/x\","
+        "        \"Type\": \"PAC\" }"
+        "    }"
+        "  ],"
+        "  \"Type\": \"UnencryptedConfiguration\""
+        "}";
+
+    policy::PolicyMap map;
+    map.Set(policy_name,
+            policy::POLICY_LEVEL_MANDATORY,
+            scope,
+            new base::StringValue(onc_policy),
+            NULL);
+    policy_provider_.UpdateChromePolicy(map);
+
+    content::RunAllPendingInMessageLoop();
+  }
+
   const chromeos::NetworkState* GetDefaultNetwork() {
-    return chromeos::NetworkHandler::Get()->network_state_handler()->
-        DefaultNetwork();
+    return chromeos::NetworkHandler::Get()->network_state_handler()
+        ->DefaultNetwork();
   }
 
   void SetProxyPref(const std::string& name, const base::Value& value) {
@@ -760,24 +826,30 @@
     SetPref(name, type, &value, true, &observed_json);
   }
 
-  void VerifyCurrentProxyServer(const std::string& expected_server) {
-    scoped_ptr<ProxyConfigDictionary> proxy_dict(
-        chromeos::proxy_config::GetProxyConfigForNetwork(*GetDefaultNetwork()));
+  void VerifyCurrentProxyServer(const std::string& expected_server,
+                                chromeos::onc::ONCSource expected_source) {
+    chromeos::onc::ONCSource actual_source;
+    scoped_ptr<ProxyConfigDictionary> proxy_dict =
+        chromeos::proxy_config::GetProxyConfigForNetwork(
+            pref_service_,
+            g_browser_process->local_state(),
+            *GetDefaultNetwork(),
+            &actual_source);
     std::string actual_proxy_server;
     EXPECT_TRUE(proxy_dict->GetProxyServer(&actual_proxy_server));
     EXPECT_EQ(expected_server, actual_proxy_server);
+    EXPECT_EQ(expected_source, actual_source);
   }
 };
 
 // Verifies that proxy settings are correctly pushed to JavaScript during
 // initialization of the proxy settings page.
-IN_PROC_BROWSER_TEST_F(ProxyPreferencesBrowserTest,
-                       ChromeOSInitializeProxy) {
+IN_PROC_BROWSER_TEST_F(ProxyPreferencesBrowserTest, ChromeOSInitializeProxy) {
   // Boolean pref.
   pref_names_.push_back(chromeos::kProxySingle);
   non_default_values_.push_back(new base::FundamentalValue(true));
 
-  // Integer pref.
+  // Integer prefs.
   pref_names_.push_back(chromeos::kProxySingleHttpPort);
   non_default_values_.push_back(new base::FundamentalValue(8080));
 
@@ -792,10 +864,91 @@
   list->Append(new base::StringValue("1.2.3.4:22"));
   non_default_values_.push_back(list);
 
+  // Verify that no policy is presented to the UI. This must be verified on the
+  // kProxyType and the kUseSharedProxies prefs.
+  pref_names_.push_back(chromeos::kProxyType);
+  non_default_values_.push_back(new base::FundamentalValue(2));
+
+  pref_names_.push_back(prefs::kUseSharedProxies);
+  non_default_values_.push_back(new base::FundamentalValue(false));
+
   std::string observed_json;
   SetupJavaScriptTestEnvironment(pref_names_, &observed_json);
-  VerifyObservedPrefs(observed_json, pref_names_, non_default_values_,
-                      "", false, false);
+  VerifyObservedPrefs(
+      observed_json, pref_names_, non_default_values_, "", false, false);
+}
+
+IN_PROC_BROWSER_TEST_F(ProxyPreferencesBrowserTest, ONCPolicy) {
+  SetONCPolicy(policy::key::kOpenNetworkConfiguration,
+               policy::POLICY_SCOPE_USER);
+
+  // Verify that per-network policy is presented to the UI. This must be
+  // verified on the kProxyType.
+  pref_names_.push_back(chromeos::kProxyType);
+  non_default_values_.push_back(new base::FundamentalValue(3));
+
+  std::string observed_json;
+  SetupJavaScriptTestEnvironment(pref_names_, &observed_json);
+  VerifyObservedPrefs(
+      observed_json, pref_names_, non_default_values_, "policy", true, false);
+
+  // Verify that 'use-shared-proxies' is not affected by per-network policy.
+  pref_names_.clear();
+  STLDeleteElements(&non_default_values_);
+  pref_names_.push_back(prefs::kUseSharedProxies);
+  non_default_values_.push_back(new base::FundamentalValue(false));
+
+  SetupJavaScriptTestEnvironment(pref_names_, &observed_json);
+  VerifyObservedPrefs(
+      observed_json, pref_names_, non_default_values_, "", false, false);
+}
+
+IN_PROC_BROWSER_TEST_F(ProxyPreferencesBrowserTest, DeviceONCPolicy) {
+  SetONCPolicy(policy::key::kDeviceOpenNetworkConfiguration,
+               policy::POLICY_SCOPE_MACHINE);
+
+  // Verify that the policy is presented to the UI. This verification must be
+  // done on the kProxyType pref.
+  pref_names_.push_back(chromeos::kProxyType);
+  non_default_values_.push_back(new base::FundamentalValue(3));
+
+  std::string observed_json;
+  SetupJavaScriptTestEnvironment(pref_names_, &observed_json);
+  VerifyObservedPrefs(
+      observed_json, pref_names_, non_default_values_, "policy", true, false);
+
+  // Verify that 'use-shared-proxies' is not affected by per-network policy.
+  pref_names_.clear();
+  STLDeleteElements(&non_default_values_);
+  pref_names_.push_back(prefs::kUseSharedProxies);
+  non_default_values_.push_back(new base::FundamentalValue(false));
+
+  SetupJavaScriptTestEnvironment(pref_names_, &observed_json);
+  VerifyObservedPrefs(
+      observed_json, pref_names_, non_default_values_, "", false, false);
+}
+
+IN_PROC_BROWSER_TEST_F(ProxyPreferencesBrowserTest, UserProxyPolicy) {
+  policy_names_.push_back(policy::key::kProxyMode);
+  default_values_.push_back(
+      new base::StringValue(ProxyPrefs::kAutoDetectProxyModeName));
+  SetUserPolicies(
+      policy_names_, default_values_, policy::POLICY_LEVEL_MANDATORY);
+  content::RunAllPendingInMessageLoop();
+
+  // Verify that the policy is presented to the UI. This verification must be
+  // done on the kProxyType pref.
+  pref_names_.push_back(chromeos::kProxyType);
+  non_default_values_.push_back(new base::FundamentalValue(3));
+
+  // Verify that 'use-shared-proxies' is controlled by the policy.
+  pref_names_.push_back(prefs::kUseSharedProxies);
+  non_default_values_.push_back(new base::FundamentalValue(false));
+
+  std::string observed_json;
+  SetupJavaScriptTestEnvironment(pref_names_, &observed_json);
+  VerifyObservedPrefs(
+      observed_json, pref_names_, non_default_values_, "policy", true, false);
 }
 
 // Verifies that modifications to the proxy settings are correctly pushed from
@@ -806,7 +959,8 @@
   SetProxyPref(chromeos::kProxySingleHttpPort, base::FundamentalValue(123));
   SetProxyPref(chromeos::kProxySingleHttp, base::StringValue("www.adomain.xy"));
 
-  VerifyCurrentProxyServer("www.adomain.xy:123");
+  VerifyCurrentProxyServer("www.adomain.xy:123",
+                           chromeos::onc::ONC_SOURCE_NONE);
 }
 
 // Verify that default proxy ports are used and that ports can be updated
@@ -825,7 +979,8 @@
 
   // Verify default ports.
   VerifyCurrentProxyServer(
-      "http=a.com:80;https=4.3.2.1:80;ftp=c.com:80;socks=socks4://d.com:1080");
+      "http=a.com:80;https=4.3.2.1:80;ftp=c.com:80;socks=socks4://d.com:1080",
+      chromeos::onc::ONC_SOURCE_NONE);
 
   // Set and verify the ports.
   SetProxyPref(chromeos::kProxyHttpPort, base::FundamentalValue(1));
@@ -834,7 +989,8 @@
   SetProxyPref(chromeos::kProxySocksPort, base::FundamentalValue(4));
 
   VerifyCurrentProxyServer(
-      "http=a.com:1;https=4.3.2.1:2;ftp=c.com:3;socks=socks4://d.com:4");
+      "http=a.com:1;https=4.3.2.1:2;ftp=c.com:3;socks=socks4://d.com:4",
+      chromeos::onc::ONC_SOURCE_NONE);
 }
 
 #endif
diff --git a/chrome/browser/ui/webui/options/preferences_browsertest.h b/chrome/browser/ui/webui/options/preferences_browsertest.h
index f8445d4..6cf4281 100644
--- a/chrome/browser/ui/webui/options/preferences_browsertest.h
+++ b/chrome/browser/ui/webui/options/preferences_browsertest.h
@@ -172,7 +172,7 @@
   // the tab.
   content::RenderViewHost* render_view_host_;
 
-  // Mock user policy provider.
+  // Mock policy provider for both user and device policies.
   policy::MockConfigurationPolicyProvider policy_provider_;
 
   // Pref change registrar that detects changes to user-modified pref values
diff --git a/chrome/browser/ui/webui/plugins_ui.cc b/chrome/browser/ui/webui/plugins_ui.cc
index fa809f1..94b57dd 100644
--- a/chrome/browser/ui/webui/plugins_ui.cc
+++ b/chrome/browser/ui/webui/plugins_ui.cc
@@ -52,8 +52,8 @@
 
 using content::PluginService;
 using content::WebContents;
+using content::WebPluginInfo;
 using content::WebUIMessageHandler;
-using webkit::WebPluginInfo;
 
 namespace {
 
@@ -167,7 +167,7 @@
   void LoadPlugins();
 
   // Called on the UI thread when the plugin information is ready.
-  void PluginsLoaded(const std::vector<webkit::WebPluginInfo>& plugins);
+  void PluginsLoaded(const std::vector<WebPluginInfo>& plugins);
 
   content::NotificationRegistrar registrar_;
 
@@ -329,7 +329,7 @@
 }
 
 void PluginsDOMHandler::PluginsLoaded(
-    const std::vector<webkit::WebPluginInfo>& plugins) {
+    const std::vector<WebPluginInfo>& plugins) {
   Profile* profile = Profile::FromWebUI(web_ui());
   PluginPrefs* plugin_prefs = PluginPrefs::GetForProfile(profile).get();
 
@@ -371,7 +371,7 @@
       plugin_file->SetString("type", PluginTypeToString(group_plugin.type));
 
       ListValue* mime_types = new ListValue();
-      const std::vector<webkit::WebPluginMimeType>& plugin_mime_types =
+      const std::vector<content::WebPluginMimeType>& plugin_mime_types =
           group_plugin.mime_types;
       for (size_t k = 0; k < plugin_mime_types.size(); ++k) {
         DictionaryValue* mime_type = new DictionaryValue();
diff --git a/chrome/browser/ui/webui/predictors/predictors_handler.cc b/chrome/browser/ui/webui/predictors/predictors_handler.cc
index 14c88cf..3536ac9 100644
--- a/chrome/browser/ui/webui/predictors/predictors_handler.cc
+++ b/chrome/browser/ui/webui/predictors/predictors_handler.cc
@@ -13,7 +13,7 @@
 #include "chrome/browser/predictors/resource_prefetch_predictor_tables.h"
 #include "chrome/browser/profiles/profile.h"
 #include "content/public/browser/web_ui.h"
-#include "webkit/glue/resource_type.h"
+#include "webkit/common/resource_type.h"
 
 using predictors::AutocompleteActionPredictor;
 using predictors::ResourcePrefetchPredictor;
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_handler.cc b/chrome/browser/ui/webui/print_preview/print_preview_handler.cc
index 98b2188..32e6012 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_handler.cc
+++ b/chrome/browser/ui/webui/print_preview/print_preview_handler.cc
@@ -62,7 +62,7 @@
 #include "printing/page_range.h"
 #include "printing/page_size_margins.h"
 #include "printing/print_settings.h"
-#include "third_party/icu/public/i18n/unicode/ulocdata.h"
+#include "third_party/icu/source/i18n/unicode/ulocdata.h"
 
 #if defined(OS_CHROMEOS)
 // TODO(kinaba): provide more non-intrusive way for handling local/remote
@@ -92,8 +92,8 @@
   FALLBACK_TO_ADVANCED_SETTINGS_DIALOG,
   PREVIEW_FAILED,
   PREVIEW_STARTED,
-  INITIATOR_TAB_CRASHED,  // UNUSED
-  INITIATOR_TAB_CLOSED,
+  INITIATOR_CRASHED,  // UNUSED
+  INITIATOR_CLOSED,
   PRINT_WITH_CLOUD_PRINT,
   USERACTION_BUCKET_BOUNDARY
 };
@@ -157,8 +157,8 @@
 
 // Name of a dictionary field holding cloud print related data;
 const char kAppState[] = "appState";
-// Name of a dictionary field holding the initiator tab title.
-const char kInitiatorTabTitle[] = "initiatorTabTitle";
+// Name of a dictionary field holding the initiator title.
+const char kInitiatorTitle[] = "initiatorTitle";
 // Name of a dictionary field holding the measurement system according to the
 // locale.
 const char kMeasurementSystem[] = "measurementSystem";
@@ -445,9 +445,9 @@
   // Increment request count.
   ++regenerate_preview_request_count_;
 
-  WebContents* initiator_tab = GetInitiatorTab();
-  if (!initiator_tab) {
-    ReportUserActionHistogram(INITIATOR_TAB_CLOSED);
+  WebContents* initiator = GetInitiator();
+  if (!initiator) {
+    ReportUserActionHistogram(INITIATOR_CLOSED);
     print_preview_ui->OnClosePrintPreviewDialog();
     return;
   }
@@ -461,9 +461,9 @@
   }
   if (display_header_footer) {
     settings->SetString(printing::kSettingHeaderFooterTitle,
-                        initiator_tab->GetTitle());
+                        initiator->GetTitle());
     std::string url;
-    NavigationEntry* entry = initiator_tab->GetController().GetActiveEntry();
+    NavigationEntry* entry = initiator->GetController().GetActiveEntry();
     if (entry)
       url = entry->GetVirtualURL().spec();
     settings->SetString(printing::kSettingHeaderFooterURL, url);
@@ -491,7 +491,7 @@
   }
 
   VLOG(1) << "Print preview request start";
-  RenderViewHost* rvh = initiator_tab->GetRenderViewHost();
+  RenderViewHost* rvh = initiator->GetRenderViewHost();
   rvh->Send(new PrintMsg_PrintPreview(rvh->GetRoutingID(), *settings));
 }
 
@@ -503,9 +503,9 @@
   UMA_HISTOGRAM_COUNTS("PrintPreview.RegeneratePreviewRequest.BeforePrint",
                        regenerate_preview_request_count_);
 
-  WebContents* initiator_tab = GetInitiatorTab();
-  if (initiator_tab) {
-    RenderViewHost* rvh = initiator_tab->GetRenderViewHost();
+  WebContents* initiator = GetInitiator();
+  if (initiator) {
+    RenderViewHost* rvh = initiator->GetRenderViewHost();
     rvh->Send(new PrintMsg_ResetScriptedPrintCount(rvh->GetRoutingID()));
   }
 
@@ -556,15 +556,15 @@
     ReportUserActionHistogram(PRINT_TO_PRINTER);
     ReportPrintSettingsStats(*settings);
 
-    // This tries to activate the initiator tab as well, so do not clear the
-    // association with the initiator tab yet.
+    // This tries to activate the initiator as well, so do not clear the
+    // association with the initiator yet.
     PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(
         web_ui()->GetController());
     print_preview_ui->OnHidePreviewDialog();
 
-    // Do this so the initiator tab can open a new print preview dialog, while
-    // the current print preview dialog is still handling its print job.
-    ClearInitiatorTabDetails();
+    // Do this so the initiator can open a new print preview dialog, while the
+    // current print preview dialog is still handling its print job.
+    ClearInitiatorDetails();
 
     // The PDF being printed contains only the pages that the user selected,
     // so ignore the page range and print all pages.
@@ -583,9 +583,9 @@
     // printing has finished. Then the dialog closes and PrintPreviewDone() gets
     // called. In the case below, since the preview dialog will be hidden and
     // not closed, we need to make this call.
-    if (initiator_tab) {
+    if (initiator) {
       printing::PrintViewManager* print_view_manager =
-          printing::PrintViewManager::FromWebContents(initiator_tab);
+          printing::PrintViewManager::FromWebContents(initiator);
       print_view_manager->PrintPreviewDone();
     }
   }
@@ -601,7 +601,7 @@
     PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(
         web_ui()->GetController());
     // Pre-populating select file dialog with print job title.
-    string16 print_job_title_utf16 = print_preview_ui->initiator_tab_title();
+    string16 print_job_title_utf16 = print_preview_ui->initiator_title();
 
 #if defined(OS_WIN)
     base::FilePath::StringType print_job_title(print_job_title_utf16);
@@ -627,11 +627,11 @@
 
 void PrintPreviewHandler::HandleCancelPendingPrintRequest(
     const ListValue* /*args*/) {
-  WebContents* initiator_tab = GetInitiatorTab();
-  if (initiator_tab)
-    ClearInitiatorTabDetails();
-  gfx::NativeWindow parent = initiator_tab ?
-      initiator_tab->GetView()->GetTopLevelNativeWindow() :
+  WebContents* initiator = GetInitiator();
+  if (initiator)
+    ClearInitiatorDetails();
+  gfx::NativeWindow parent = initiator ?
+      initiator->GetView()->GetTopLevelNativeWindow() :
       NULL;
   chrome::ShowPrintErrorDialog(parent);
 }
@@ -737,12 +737,12 @@
   ReportStats();
   ReportUserActionHistogram(FALLBACK_TO_ADVANCED_SETTINGS_DIALOG);
 
-  WebContents* initiator_tab = GetInitiatorTab();
-  if (!initiator_tab)
+  WebContents* initiator = GetInitiator();
+  if (!initiator)
     return;
 
   printing::PrintViewManager* print_view_manager =
-      printing::PrintViewManager::FromWebContents(initiator_tab);
+      printing::PrintViewManager::FromWebContents(initiator);
   print_view_manager->set_observer(this);
   print_view_manager->PrintForSystemDialogNow();
 
@@ -848,7 +848,7 @@
   std::string url;
   if (!args->GetString(0, &url))
     return;
-  Browser* browser = chrome::FindBrowserWithWebContents(GetInitiatorTab());
+  Browser* browser = chrome::FindBrowserWithWebContents(GetInitiator());
   if (!browser)
     return;
   chrome::AddSelectedTabWithURL(browser,
@@ -863,8 +863,8 @@
       web_ui()->GetController());
 
   base::DictionaryValue initial_settings;
-  initial_settings.SetString(kInitiatorTabTitle,
-                             print_preview_ui->initiator_tab_title());
+  initial_settings.SetString(kInitiatorTitle,
+                             print_preview_ui->initiator_title());
   initial_settings.SetBoolean(printing::kSettingPreviewModifiable,
                               print_preview_ui->source_is_modifiable());
   initial_settings.SetString(printing::kSettingPrinterName, default_printer);
@@ -944,12 +944,12 @@
   web_ui()->CallJavascriptFunction("printToCloud", data_value);
 }
 
-WebContents* PrintPreviewHandler::GetInitiatorTab() const {
+WebContents* PrintPreviewHandler::GetInitiator() const {
   printing::PrintPreviewDialogController* dialog_controller =
       printing::PrintPreviewDialogController::GetInstance();
   if (!dialog_controller)
     return NULL;
-  return dialog_controller->GetInitiatorTab(preview_web_contents());
+  return dialog_controller->GetInitiator(preview_web_contents());
 }
 
 void PrintPreviewHandler::OnPrintDialogShown() {
@@ -991,12 +991,12 @@
 }
 
 void PrintPreviewHandler::OnPrintPreviewDialogDestroyed() {
-  WebContents* initiator_tab = GetInitiatorTab();
-  if (!initiator_tab)
+  WebContents* initiator = GetInitiator();
+  if (!initiator)
     return;
 
   printing::PrintViewManager* print_view_manager =
-      printing::PrintViewManager::FromWebContents(initiator_tab);
+      printing::PrintViewManager::FromWebContents(initiator);
   print_view_manager->set_observer(NULL);
 }
 
@@ -1055,18 +1055,18 @@
   print_preview_ui->OnFileSelectionCancelled();
 }
 
-void PrintPreviewHandler::ClearInitiatorTabDetails() {
-  WebContents* initiator_tab = GetInitiatorTab();
-  if (!initiator_tab)
+void PrintPreviewHandler::ClearInitiatorDetails() {
+  WebContents* initiator = GetInitiator();
+  if (!initiator)
     return;
 
-  // We no longer require the initiator tab details. Remove those details
-  // associated with the preview dialog to allow the initiator tab to create
-  // another preview dialog.
+  // We no longer require the initiator details. Remove those details associated
+  // with the preview dialog to allow the initiator to create another preview
+  // dialog.
   printing::PrintPreviewDialogController* dialog_controller =
       printing::PrintPreviewDialogController::GetInstance();
   if (dialog_controller)
-    dialog_controller->EraseInitiatorTabInfo(preview_web_contents());
+    dialog_controller->EraseInitiatorInfo(preview_web_contents());
 }
 
 bool PrintPreviewHandler::GetPreviewDataAndTitle(
@@ -1085,7 +1085,7 @@
   DCHECK(tmp_data->size() && tmp_data->front());
 
   *data = tmp_data;
-  *title = print_preview_ui->initiator_tab_title();
+  *title = print_preview_ui->initiator_title();
   return true;
 }
 
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_handler.h b/chrome/browser/ui/webui/print_preview/print_preview_handler.h
index 6dde25d..36ec0a9 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_handler.h
+++ b/chrome/browser/ui/webui/print_preview/print_preview_handler.h
@@ -182,8 +182,8 @@
   // Asks the browser to show the cloud print dialog.
   void PrintWithCloudPrintDialog();
 
-  // Gets the initiator tab for the print preview dialog.
-  content::WebContents* GetInitiatorTab() const;
+  // Gets the initiator for the print preview dialog.
+  content::WebContents* GetInitiator() const;
 
   // Closes the preview dialog.
   void ClosePreviewDialog();
@@ -191,8 +191,8 @@
   // Adds all the recorded stats taken so far to histogram counts.
   void ReportStats();
 
-  // Clears initiator tab details for the print preview dialog.
-  void ClearInitiatorTabDetails();
+  // Clears initiator details for the print preview dialog.
+  void ClearInitiatorDetails();
 
   // Posts a task to save |data| to pdf at |print_to_pdf_path_|.
   void PostPrintToPdfTask();
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_ui.cc b/chrome/browser/ui/webui/print_preview/print_preview_ui.cc
index 142ac95..ca4c7e4 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_ui.cc
+++ b/chrome/browser/ui/webui/print_preview/print_preview_ui.cc
@@ -388,9 +388,9 @@
   return print_preview_data_service()->GetAvailableDraftPageCount(id_);
 }
 
-void PrintPreviewUI::SetInitiatorTabTitle(
+void PrintPreviewUI::SetInitiatorTitle(
     const string16& job_title) {
-  initiator_tab_title_ = job_title;
+  initiator_title_ = job_title;
 }
 
 // static
@@ -431,7 +431,7 @@
   OnClosePrintPreviewDialog();
 }
 
-void PrintPreviewUI::OnInitiatorTabClosed() {
+void PrintPreviewUI::OnInitiatorClosed() {
   WebContents* preview_dialog = web_ui()->GetWebContents();
   printing::BackgroundPrintingManager* background_printing_manager =
       g_browser_process->background_printing_manager();
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 51fdd02..1cd81e3 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_ui.h
+++ b/chrome/browser/ui/webui/print_preview/print_preview_ui.h
@@ -53,9 +53,9 @@
   int GetAvailableDraftPageCount();
 
   // Setters
-  void SetInitiatorTabTitle(const string16& initiator_tab_title);
+  void SetInitiatorTitle(const string16& initiator_title);
 
-  string16 initiator_tab_title() { return initiator_tab_title_; }
+  string16 initiator_title() { return initiator_title_; }
 
   bool source_is_modifiable() { return source_is_modifiable_; }
 
@@ -109,8 +109,8 @@
   void OnReusePreviewData(int preview_request_id);
 
   // Notifies the Web UI that preview dialog has been destroyed. This is the
-  // last chance to communicate with the initiator tab before the association
-  // is erased.
+  // last chance to communicate with the initiator before the association is
+  // erased.
   void OnPrintPreviewDialogDestroyed();
 
   // Notifies the Web UI that the print preview failed to render.
@@ -120,9 +120,9 @@
   // closed, which may occur for several reasons, e.g. tab closure or crash.
   void OnPrintPreviewDialogClosed();
 
-  // Notifies the Web UI that initiator tab is closed, so we can disable all the
-  // controls that need the initiator tab for generating the preview data.
-  void OnInitiatorTabClosed();
+  // Notifies the Web UI that initiator is closed, so we can disable all the
+  // controls that need the initiator for generating the preview data.
+  void OnInitiatorClosed();
 
   // Notifies the Web UI renderer that file selection has been cancelled.
   void OnFileSelectionCancelled();
@@ -181,9 +181,9 @@
   // Indicates whether only the selection should be printed.
   bool print_selection_only_;
 
-  // Store the initiator tab title, used for populating the print preview dialog
+  // Store the initiator title, used for populating the print preview dialog
   // title.
-  string16 initiator_tab_title_;
+  string16 initiator_title_;
 
   // Keeps track of whether OnClosePrintPreviewDialog() has been called or not.
   bool dialog_closed_;
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_ui_unittest.cc b/chrome/browser/ui/webui/print_preview/print_preview_ui_unittest.cc
index 18cdd80..0f48f49 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_ui_unittest.cc
+++ b/chrome/browser/ui/webui/print_preview/print_preview_ui_unittest.cc
@@ -20,7 +20,6 @@
 #include "content/public/browser/site_instance.h"
 #include "content/public/browser/web_contents.h"
 #include "printing/print_job_constants.h"
-#include "webkit/plugins/npapi/mock_plugin_list.h"
 
 using content::WebContents;
 using web_modal::WebContentsModalDialogManager;
@@ -62,26 +61,24 @@
   chrome::NewTab(browser());
 }
 
-// Create/Get a preview tab for initiator tab.
+// Create/Get a preview tab for initiator.
 TEST_F(PrintPreviewUIUnitTest, PrintPreviewData) {
-  WebContents* initiator_tab =
-      browser()->tab_strip_model()->GetActiveWebContents();
-  ASSERT_TRUE(initiator_tab);
-  EXPECT_FALSE(IsShowingWebContentsModalDialog(initiator_tab));
+  WebContents* initiator = browser()->tab_strip_model()->GetActiveWebContents();
+  ASSERT_TRUE(initiator);
+  EXPECT_FALSE(IsShowingWebContentsModalDialog(initiator));
 
   printing::PrintPreviewDialogController* controller =
       printing::PrintPreviewDialogController::GetInstance();
   ASSERT_TRUE(controller);
 
   printing::PrintViewManager* print_view_manager =
-      printing::PrintViewManager::FromWebContents(initiator_tab);
+      printing::PrintViewManager::FromWebContents(initiator);
   print_view_manager->PrintPreviewNow(false);
-  WebContents* preview_dialog =
-      controller->GetOrCreatePreviewDialog(initiator_tab);
+  WebContents* preview_dialog = controller->GetOrCreatePreviewDialog(initiator);
 
-  EXPECT_NE(initiator_tab, preview_dialog);
+  EXPECT_NE(initiator, preview_dialog);
   EXPECT_EQ(1, browser()->tab_strip_model()->count());
-  EXPECT_TRUE(IsShowingWebContentsModalDialog(initiator_tab));
+  EXPECT_TRUE(IsShowingWebContentsModalDialog(initiator));
 
   PrintPreviewUI* preview_ui = static_cast<PrintPreviewUI*>(
       preview_dialog->GetWebUI()->GetController());
@@ -120,23 +117,21 @@
 
 // Set and get the individual draft pages.
 TEST_F(PrintPreviewUIUnitTest, PrintPreviewDraftPages) {
-  WebContents* initiator_tab =
-      browser()->tab_strip_model()->GetActiveWebContents();
-  ASSERT_TRUE(initiator_tab);
+  WebContents* initiator = browser()->tab_strip_model()->GetActiveWebContents();
+  ASSERT_TRUE(initiator);
 
   printing::PrintPreviewDialogController* controller =
       printing::PrintPreviewDialogController::GetInstance();
   ASSERT_TRUE(controller);
 
   printing::PrintViewManager* print_view_manager =
-      printing::PrintViewManager::FromWebContents(initiator_tab);
+      printing::PrintViewManager::FromWebContents(initiator);
   print_view_manager->PrintPreviewNow(false);
-  WebContents* preview_dialog =
-      controller->GetOrCreatePreviewDialog(initiator_tab);
+  WebContents* preview_dialog = controller->GetOrCreatePreviewDialog(initiator);
 
-  EXPECT_NE(initiator_tab, preview_dialog);
+  EXPECT_NE(initiator, preview_dialog);
   EXPECT_EQ(1, browser()->tab_strip_model()->count());
-  EXPECT_TRUE(IsShowingWebContentsModalDialog(initiator_tab));
+  EXPECT_TRUE(IsShowingWebContentsModalDialog(initiator));
 
   PrintPreviewUI* preview_ui = static_cast<PrintPreviewUI*>(
       preview_dialog->GetWebUI()->GetController());
@@ -182,23 +177,21 @@
 
 // Test the browser-side print preview cancellation functionality.
 TEST_F(PrintPreviewUIUnitTest, GetCurrentPrintPreviewStatus) {
-  WebContents* initiator_tab =
-      browser()->tab_strip_model()->GetActiveWebContents();
-  ASSERT_TRUE(initiator_tab);
+  WebContents* initiator = browser()->tab_strip_model()->GetActiveWebContents();
+  ASSERT_TRUE(initiator);
 
   printing::PrintPreviewDialogController* controller =
       printing::PrintPreviewDialogController::GetInstance();
   ASSERT_TRUE(controller);
 
   printing::PrintViewManager* print_view_manager =
-      printing::PrintViewManager::FromWebContents(initiator_tab);
+      printing::PrintViewManager::FromWebContents(initiator);
   print_view_manager->PrintPreviewNow(false);
-  WebContents* preview_dialog =
-      controller->GetOrCreatePreviewDialog(initiator_tab);
+  WebContents* preview_dialog = controller->GetOrCreatePreviewDialog(initiator);
 
-  EXPECT_NE(initiator_tab, preview_dialog);
+  EXPECT_NE(initiator, preview_dialog);
   EXPECT_EQ(1, browser()->tab_strip_model()->count());
-  EXPECT_TRUE(IsShowingWebContentsModalDialog(initiator_tab));
+  EXPECT_TRUE(IsShowingWebContentsModalDialog(initiator));
 
   PrintPreviewUI* preview_ui = static_cast<PrintPreviewUI*>(
       preview_dialog->GetWebUI()->GetController());
diff --git a/chrome/browser/ui/webui/signin/user_chooser_screen_handler.cc b/chrome/browser/ui/webui/signin/user_chooser_screen_handler.cc
new file mode 100644
index 0000000..c46a843
--- /dev/null
+++ b/chrome/browser/ui/webui/signin/user_chooser_screen_handler.cc
@@ -0,0 +1,229 @@
+// Copyright 2013 The Chromium Authors. 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/signin/user_chooser_screen_handler.h"
+
+#include "base/bind.h"
+#include "base/values.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_info_cache.h"
+#include "chrome/browser/profiles/profile_info_util.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/profiles/profile_window.h"
+#include "chrome/browser/ui/browser_commands.h"
+#include "chrome/browser/ui/browser_finder.h"
+#include "chrome/browser/ui/singleton_tabs.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_ui.h"
+#include "grit/browser_resources.h"
+#include "grit/chromium_strings.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_util.h"
+#include "ui/webui/web_ui_util.h"
+
+namespace {
+// User dictionary keys.
+const char kKeyUsername[] = "username";
+const char kKeyDisplayName[]= "displayName";
+const char kKeyEmailAddress[] = "emailAddress";
+const char kKeyPublicAccount[] = "publicAccount";
+const char kKeyLocallyManagedUser[] = "locallyManagedUser";
+const char kKeySignedIn[] = "signedIn";
+const char kKeyCanRemove[] = "canRemove";
+const char kKeyIsOwner[] = "isOwner";
+const char kKeyIsDesktop[] = "isDesktopUser";
+const char kKeyAvatarUrl[] = "userImage";
+const char kKeyNeedsSignin[] = "needsSignin";
+const char kGAIAPictureFileNameKey[] = "gaia_picture_file_name";
+
+// Max number of users to show.
+const size_t kMaxUsers = 18;
+
+// Type of the login screen UI that is currently presented to user.
+const char kSourceGaiaSignin[] = "gaia-signin";
+const char kSourceAccountPicker[] = "account-picker";
+
+// JS API callback names.
+const char kJsApiUserChooserInitialize[] = "userChooserInitialize";
+const char kJsApiUserChooserAddUser[] = "addUser";
+const char kJsApiUserChooserLaunchGuest[] = "launchGuest";
+const char kJsApiUserChooserLaunchUser[] = "launchUser";
+const char kJsApiUserChooserRemoveUser[] = "removeUser";
+
+void HandleAndDoNothing(const base::ListValue* args) {
+}
+
+} // namespace
+
+UserChooserScreenHandler::UserChooserScreenHandler() {
+}
+
+UserChooserScreenHandler::~UserChooserScreenHandler() {
+}
+
+void UserChooserScreenHandler::HandleInitialize(const base::ListValue* args) {
+  SendUserList();
+  web_ui()->CallJavascriptFunction("cr.ui.Oobe.showUserChooserScreen");
+}
+
+void UserChooserScreenHandler::HandleAddUser(const base::ListValue* args) {
+  // TODO(noms): Should redirect to a sign in page.
+  chrome::ShowSingletonTab(chrome::FindBrowserWithWebContents(
+      web_ui()->GetWebContents()),
+      GURL("chrome://settings/createProfile"));
+}
+
+void UserChooserScreenHandler::HandleRemoveUser(const base::ListValue* args) {
+  // TODO(noms): Should delete the user.
+  chrome::ShowSingletonTab(chrome::FindBrowserWithWebContents(
+      web_ui()->GetWebContents()),
+      GURL("chrome://settings/search#Users"));
+}
+
+void UserChooserScreenHandler::HandleLaunchGuest(const base::ListValue* args) {
+  // TODO(noms): Once guest mode is ready, should launch a guest browser.
+  chrome::NewIncognitoWindow(chrome::FindBrowserWithWebContents(
+      web_ui()->GetWebContents()));
+}
+
+void UserChooserScreenHandler::HandleLaunchUser(const base::ListValue* args) {
+  string16 emailAddress;
+  string16 displayName;
+
+  if (!args->GetString(0, &emailAddress) ||
+      !args->GetString(1, &displayName)) {
+    NOTREACHED();
+    return;
+  }
+
+  ProfileInfoCache& info_cache =
+      g_browser_process->profile_manager()->GetProfileInfoCache();
+  chrome::HostDesktopType desktop_type = chrome::GetActiveDesktop();
+
+  for (size_t i = 0; i < info_cache.GetNumberOfProfiles(); ++i) {
+    if (info_cache.GetUserNameOfProfileAtIndex(i) == emailAddress &&
+        info_cache.GetNameOfProfileAtIndex(i) == displayName) {
+      base::FilePath path = info_cache.GetPathOfProfileAtIndex(i);
+      profiles::SwitchToProfile(path, desktop_type, true);
+      break;
+    }
+  }
+}
+
+void UserChooserScreenHandler::RegisterMessages() {
+  web_ui()->RegisterMessageCallback(kJsApiUserChooserInitialize,
+      base::Bind(&UserChooserScreenHandler::HandleInitialize,
+                 base::Unretained(this)));
+  web_ui()->RegisterMessageCallback(kJsApiUserChooserAddUser,
+      base::Bind(&UserChooserScreenHandler::HandleAddUser,
+                 base::Unretained(this)));
+  web_ui()->RegisterMessageCallback(kJsApiUserChooserLaunchGuest,
+      base::Bind(&UserChooserScreenHandler::HandleLaunchGuest,
+                 base::Unretained(this)));
+  web_ui()->RegisterMessageCallback(kJsApiUserChooserLaunchUser,
+      base::Bind(&UserChooserScreenHandler::HandleLaunchUser,
+                 base::Unretained(this)));
+  web_ui()->RegisterMessageCallback(kJsApiUserChooserRemoveUser,
+      base::Bind(&UserChooserScreenHandler::HandleRemoveUser,
+                 base::Unretained(this)));
+
+  const content::WebUI::MessageCallback& kDoNothingCallback =
+      base::Bind(&HandleAndDoNothing);
+
+  // Unused callbacks from screen_account_picker.js
+  web_ui()->RegisterMessageCallback("accountPickerReady", kDoNothingCallback);
+  web_ui()->RegisterMessageCallback("loginUIStateChanged", kDoNothingCallback);
+  web_ui()->RegisterMessageCallback("hideCaptivePortal", kDoNothingCallback);
+  // Unused callbacks from display_manager.js
+  web_ui()->RegisterMessageCallback("showAddUser", kDoNothingCallback);
+  web_ui()->RegisterMessageCallback("loadWallpaper", kDoNothingCallback);
+  web_ui()->RegisterMessageCallback("updateCurrentScreen", kDoNothingCallback);
+  web_ui()->RegisterMessageCallback("loginVisible", kDoNothingCallback);
+  // Unused callbacks from user_pod_row.js
+  web_ui()->RegisterMessageCallback("userImagesLoaded", kDoNothingCallback);
+}
+
+void UserChooserScreenHandler::GetLocalizedValues(
+    base::DictionaryValue* localized_strings) {
+  // For Control Bar.
+  localized_strings->SetString("signedIn",
+      l10n_util::GetStringUTF16(IDS_SCREEN_LOCK_ACTIVE_USER));
+  localized_strings->SetString("signinButton",
+      l10n_util::GetStringUTF16(IDS_LOGIN_BUTTON));
+  localized_strings->SetString("addUser",
+      l10n_util::GetStringUTF16(IDS_ADD_USER_BUTTON));
+  localized_strings->SetString("cancel", l10n_util::GetStringUTF16(IDS_CANCEL));
+  localized_strings->SetString("browseAsGuest",
+      l10n_util::GetStringUTF16(IDS_GO_INCOGNITO_BUTTON));
+  localized_strings->SetString("signOutUser",
+      l10n_util::GetStringUTF16(IDS_SCREEN_LOCK_SIGN_OUT));
+
+  // For AccountPickerScreen.
+  localized_strings->SetString("screenType", "login-add-user");
+  localized_strings->SetString("highlightStrength", "normal");
+  localized_strings->SetString("title", "User Chooser");
+  localized_strings->SetString("passwordHint",
+      l10n_util::GetStringUTF16(IDS_LOGIN_POD_EMPTY_PASSWORD_TEXT));
+  localized_strings->SetString("podMenuButtonAccessibleName",
+      l10n_util::GetStringUTF16(IDS_LOGIN_POD_MENU_BUTTON_ACCESSIBLE_NAME));
+  localized_strings->SetString("podMenuRemoveItemAccessibleName",
+      l10n_util::GetStringUTF16(
+          IDS_LOGIN_POD_MENU_REMOVE_ITEM_ACCESSIBLE_NAME));
+  localized_strings->SetString("removeUser",
+      l10n_util::GetStringUTF16(IDS_LOGIN_POD_REMOVE_USER));
+  localized_strings->SetString("passwordFieldAccessibleName",
+      l10n_util::GetStringUTF16(IDS_LOGIN_POD_PASSWORD_FIELD_ACCESSIBLE_NAME));
+  localized_strings->SetString("bootIntoWallpaper", "off");
+
+ }
+
+void UserChooserScreenHandler::SendUserList() {
+  ListValue users_list;
+  base::FilePath current_profile_path =
+      web_ui()->GetWebContents()->GetBrowserContext()->GetPath();
+  const ProfileInfoCache& info_cache =
+      g_browser_process->profile_manager()->GetProfileInfoCache();
+
+  for (size_t i = 0; i < info_cache.GetNumberOfProfiles(); ++i) {
+    DictionaryValue* profile_value = new DictionaryValue();
+
+    base::FilePath profile_path = info_cache.GetPathOfProfileAtIndex(i);
+    bool is_active_user = (profile_path == current_profile_path);
+    bool needs_signin = info_cache.ProfileIsSigninRequiredAtIndex(i);
+
+    profile_value->SetString(
+        kKeyUsername, info_cache.GetUserNameOfProfileAtIndex(i));
+    profile_value->SetString(
+        kKeyEmailAddress, info_cache.GetUserNameOfProfileAtIndex(i));
+    profile_value->SetString(
+        kKeyDisplayName, info_cache.GetNameOfProfileAtIndex(i));
+    profile_value->SetBoolean(kKeyPublicAccount, false);
+    profile_value->SetBoolean(kKeyLocallyManagedUser, false);
+    profile_value->SetBoolean(kKeySignedIn, is_active_user);
+    profile_value->SetBoolean(kKeyNeedsSignin, needs_signin);
+    profile_value->SetBoolean(kKeyIsOwner, false);
+    profile_value->SetBoolean(kKeyCanRemove, true);
+    profile_value->SetBoolean(kKeyIsDesktop, true);
+
+    bool is_gaia_picture =
+        info_cache.IsUsingGAIAPictureOfProfileAtIndex(i) &&
+        info_cache.GetGAIAPictureOfProfileAtIndex(i);
+
+    gfx::Image icon = profiles::GetSizedAvatarIconWithBorder(
+        info_cache.GetAvatarIconOfProfileAtIndex(i), is_gaia_picture, 160, 160);
+    profile_value->SetString(kKeyAvatarUrl,
+        webui::GetBitmapDataUrl(icon.AsBitmap()));
+
+    if (is_active_user)
+      users_list.Insert(0, profile_value);
+    else
+      users_list.Append(profile_value);
+  }
+
+  web_ui()->CallJavascriptFunction("login.AccountPickerScreen.loadUsers",
+    users_list, base::FundamentalValue(false), base::FundamentalValue(true));
+}
diff --git a/chrome/browser/ui/webui/signin/user_chooser_screen_handler.h b/chrome/browser/ui/webui/signin/user_chooser_screen_handler.h
new file mode 100644
index 0000000..3dbf1f4
--- /dev/null
+++ b/chrome/browser/ui/webui/signin/user_chooser_screen_handler.h
@@ -0,0 +1,39 @@
+// Copyright 2013 The Chromium 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_SIGNIN_USER_CHOOSER_SCREEN_HANDLER_H_
+#define CHROME_BROWSER_UI_WEBUI_SIGNIN_USER_CHOOSER_SCREEN_HANDLER_H_
+
+#include "base/compiler_specific.h"
+#include "content/public/browser/web_ui_message_handler.h"
+
+namespace base {
+class DictionaryValue;
+class ListValue;
+}
+
+class UserChooserScreenHandler : public content::WebUIMessageHandler {
+ public:
+  UserChooserScreenHandler();
+  virtual ~UserChooserScreenHandler();
+
+  // WebUIMessageHandler implementation.
+  virtual void RegisterMessages() OVERRIDE;
+
+  void GetLocalizedValues(base::DictionaryValue* localized_strings);
+
+ private:
+  void HandleInitialize(const base::ListValue* args);
+  void HandleAddUser(const base::ListValue* args);
+  void HandleLaunchGuest(const base::ListValue* args);
+  void HandleLaunchUser(const base::ListValue* args);
+  void HandleRemoveUser(const base::ListValue* args);
+
+  // Sends user list to account chooser.
+  void SendUserList();
+
+  DISALLOW_COPY_AND_ASSIGN(UserChooserScreenHandler);
+};
+
+#endif  // CHROME_BROWSER_UI_WEBUI_SIGNIN_USER_CHOOSER_SCREEN_HANDLER_H_
diff --git a/chrome/browser/ui/webui/signin/user_chooser_ui.cc b/chrome/browser/ui/webui/signin/user_chooser_ui.cc
new file mode 100644
index 0000000..0664716
--- /dev/null
+++ b/chrome/browser/ui/webui/signin/user_chooser_ui.cc
@@ -0,0 +1,75 @@
+// Copyright 2013 The Chromium Authors. 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/signin/user_chooser_ui.h"
+
+#include "base/values.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/webui/signin/user_chooser_screen_handler.h"
+#include "chrome/browser/ui/webui/theme_source.h"
+#include "chrome/common/url_constants.h"
+#include "content/public/browser/web_ui.h"
+#include "content/public/browser/web_ui_data_source.h"
+#include "grit/browser_resources.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/webui/web_ui_util.h"
+
+namespace {
+  // JS file names.
+  const char kStringsJSPath[] = "strings.js";
+  const char kUserChooserJSPath[] = "user_chooser.js";
+  const char kHeaderBarJSPath[] = "header_bar.js";
+  const char kAccountPickerJSPath[] = "screen_account_picker.js";
+}
+
+UserChooserUI::UserChooserUI(content::WebUI* web_ui)
+  : WebUIController(web_ui) {
+  // The web_ui object takes ownership of the handler, and will
+  // destroy it when it (the WebUI) is destroyed.
+  user_chooser_screen_handler_ = new UserChooserScreenHandler();
+  web_ui->AddMessageHandler(user_chooser_screen_handler_);
+
+  base::DictionaryValue localized_strings;
+  GetLocalizedStrings(&localized_strings);
+
+  Profile* profile = Profile::FromWebUI(web_ui);
+  // Set up the chrome://user-chooser/ source.
+  content::WebUIDataSource::Add(profile, CreateUIDataSource(localized_strings));
+
+#if defined(ENABLE_THEMES)
+  // Set up the chrome://theme/ source
+  ThemeSource* theme = new ThemeSource(profile);
+  content::URLDataSource::Add(profile, theme);
+#endif
+}
+
+UserChooserUI::~UserChooserUI() {
+}
+
+content::WebUIDataSource* UserChooserUI::CreateUIDataSource(
+    const base::DictionaryValue& localized_strings) {
+  content::WebUIDataSource* source =
+      content::WebUIDataSource::Create(chrome::kChromeUIUserChooserHost);
+  source->SetUseJsonJSFormatV2();
+  source->AddLocalizedStrings(localized_strings);
+  source->SetJsonPath(kStringsJSPath);
+
+  source->SetDefaultResource(IDR_USER_CHOOSER_HTML);
+  source->AddResourcePath(kUserChooserJSPath, IDR_USER_CHOOSER_JS);
+
+  return source;
+}
+
+void UserChooserUI::GetLocalizedStrings(
+    base::DictionaryValue* localized_strings) {
+  user_chooser_screen_handler_->GetLocalizedValues(localized_strings);
+  webui::SetFontAndTextDirection(localized_strings);
+
+#if defined(GOOGLE_CHROME_BUILD)
+  localized_strings->SetString("buildType", "chrome");
+#else
+  localized_strings->SetString("buildType", "chromium");
+#endif
+}
+
diff --git a/chrome/browser/ui/webui/signin/user_chooser_ui.h b/chrome/browser/ui/webui/signin/user_chooser_ui.h
new file mode 100644
index 0000000..4799bd7
--- /dev/null
+++ b/chrome/browser/ui/webui/signin/user_chooser_ui.h
@@ -0,0 +1,35 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_WEBUI_SIGNIN_USER_CHOOSER_UI_H_
+#define CHROME_BROWSER_UI_WEBUI_SIGNIN_USER_CHOOSER_UI_H_
+
+#include "content/public/browser/web_ui_controller.h"
+
+class UserChooserScreenHandler;
+
+namespace base {
+class DictionaryValue;
+}
+namespace content {
+class WebUIDataSource;
+}
+
+// A WebUI dialog to display available users.
+class UserChooserUI : public content::WebUIController {
+ public:
+  explicit UserChooserUI(content::WebUI* web_ui);
+  virtual ~UserChooserUI();
+
+ private:
+  content::WebUIDataSource* CreateUIDataSource(
+      const base::DictionaryValue& localized_strings);
+  void GetLocalizedStrings(base::DictionaryValue* localized_strings);
+
+  UserChooserScreenHandler* user_chooser_screen_handler_;
+
+  DISALLOW_COPY_AND_ASSIGN(UserChooserUI);
+};
+
+#endif  // CHROME_BROWSER_UI_WEBUI_SIGNIN_USER_CHOOSER_UI_H_
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 a410d2b..5b51aaa 100644
--- a/chrome/browser/ui/webui/sync_promo/sync_promo_trial.cc
+++ b/chrome/browser/ui/webui/sync_promo/sync_promo_trial.cc
@@ -31,6 +31,8 @@
   UMA_APP_LAUNCHER_SIGNED_IN,
   UMA_APPS_PAGE_LINK_SHOWN,
   UMA_APPS_PAGE_LINK_SIGNED_IN,
+  UMA_BOOKMARK_BUBBLE_SHOWN,
+  UMA_BOOKMARK_BUBBLE_SIGNED_IN,
   UMA_MAX,
 };
 
@@ -67,6 +69,9 @@
     case SyncPromoUI::SOURCE_APPS_PAGE_LINK:
       uma = UMA_APPS_PAGE_LINK_SHOWN;
       break;
+    case SyncPromoUI::SOURCE_BOOKMARK_BUBBLE:
+      uma = UMA_BOOKMARK_BUBBLE_SHOWN;
+      break;
     case SyncPromoUI::SOURCE_UNKNOWN:
       uma = UMA_UNKNOWN_SHOWN;
       break;
@@ -74,7 +79,7 @@
       // If this assert hits, then the SyncPromoUI::Source enum has changed and
       // the UMA enum above, this switch statement and histograms.xml all need
       // to be updated to reflect that.
-      COMPILE_ASSERT(SyncPromoUI::SOURCE_UNKNOWN == 8,
+      COMPILE_ASSERT(SyncPromoUI::SOURCE_UNKNOWN == 9,
                      kSourceEnumHasChangedButNotThisSwitchStatement);
       NOTREACHED();
       break;
@@ -111,12 +116,15 @@
     case SyncPromoUI::SOURCE_APPS_PAGE_LINK:
       uma = UMA_APPS_PAGE_LINK_SIGNED_IN;
       break;
+    case SyncPromoUI::SOURCE_BOOKMARK_BUBBLE:
+      uma = UMA_BOOKMARK_BUBBLE_SIGNED_IN;
+      break;
     case SyncPromoUI::SOURCE_UNKNOWN:
       uma = UMA_UNKNOWN_SIGNED_IN;
       break;
     default:
       // This switch statement needs to be updated when the enum Source changes.
-      COMPILE_ASSERT(SyncPromoUI::SOURCE_UNKNOWN == 8,
+      COMPILE_ASSERT(SyncPromoUI::SOURCE_UNKNOWN == 9,
                      kSourceEnumHasChangedButNotThisSwitchStatement);
       NOTREACHED();
       break;
diff --git a/chrome/browser/ui/webui/sync_setup_browsertest.js b/chrome/browser/ui/webui/sync_setup_browsertest.js
index 91e3d84..d9f96bd 100644
--- a/chrome/browser/ui/webui/sync_setup_browsertest.js
+++ b/chrome/browser/ui/webui/sync_setup_browsertest.js
@@ -31,7 +31,6 @@
    * Verifies starting point is not synced.
    */
   verifyUnsynced: function() {
-    assertFalse(BrowserOptions.getInstance().setupCompleted_);
     assertFalse(BrowserOptions.getInstance().signedIn_);
   },
 
diff --git a/chrome/browser/ui/webui/sync_setup_handler.cc b/chrome/browser/ui/webui/sync_setup_handler.cc
index eab551e..491b60a 100644
--- a/chrome/browser/ui/webui/sync_setup_handler.cc
+++ b/chrome/browser/ui/webui/sync_setup_handler.cc
@@ -23,6 +23,7 @@
 #include "chrome/browser/profiles/profile_info_cache.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/profiles/profile_metrics.h"
+#include "chrome/browser/signin/signin_global_error.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"
@@ -30,7 +31,6 @@
 #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/common/chrome_switches.h"
@@ -111,37 +111,6 @@
   return type_names;
 }
 
-#if !defined(OS_CHROMEOS)
-// Signin logic not needed on ChromeOS
-void BringTabToFront(WebContents* web_contents) {
-  DCHECK(web_contents);
-  Browser* browser = chrome::FindBrowserWithWebContents(web_contents);
-  if (browser) {
-    TabStripModel* tab_strip_model = browser->tab_strip_model();
-    if (tab_strip_model) {
-      int index = tab_strip_model->GetIndexOfWebContents(web_contents);
-      if (index != TabStripModel::kNoTab)
-        tab_strip_model->ActivateTabAt(index, false);
-    }
-  }
-}
-
-void CloseTab(content::WebContents* tab) {
-  Browser* browser = chrome::FindBrowserWithWebContents(tab);
-  if (browser) {
-    TabStripModel* tab_strip_model = browser->tab_strip_model();
-    if (tab_strip_model) {
-      int index = tab_strip_model->GetIndexOfWebContents(tab);
-      if (index != TabStripModel::kNoTab) {
-        tab_strip_model->ExecuteContextMenuCommand(
-            index, TabStripModel::CommandCloseTab);
-      }
-    }
-  }
-}
-
-#endif
-
 bool GetConfiguration(const std::string& json, SyncConfigInfo* config) {
   scoped_ptr<Value> parsed_value(base::JSONReader::Read(json));
   DictionaryValue* result;
@@ -208,11 +177,6 @@
 
 SyncSetupHandler::SyncSetupHandler(ProfileManager* profile_manager)
     : configuring_sync_(false),
-#if !defined(OS_CHROMEOS)
-      last_signin_error_(GoogleServiceAuthError::NONE),
-      retry_on_signin_failure_(true),
-      active_gaia_signin_tab_(NULL),
-#endif
       profile_manager_(profile_manager) {
 }
 
@@ -332,14 +296,6 @@
   ProfileSyncService* service = GetSyncService();
   DCHECK(service);
   if (!service->sync_initialized()) {
-
-#if !defined(OS_CHROMEOS)
-    // When user tries to setup sync while the sync backend is not initialized,
-    // kick the sync backend and wait for it to be ready and show spinner until
-    // the backend gets ready.
-    retry_on_signin_failure_ = false;
-#endif
-
     service->UnsuppressAndStart();
 
     // See if it's even possible to bring up the sync backend - if not
@@ -358,8 +314,7 @@
   }
 
   // Should only get here if user is signed in and sync is initialized, so no
-  // longer need a SigninTracker or SyncStartupTracker.
-  signin_tracker_.reset();
+  // longer need a SyncStartupTracker.
   sync_startup_tracker_.reset();
   configuring_sync_ = true;
   DCHECK(service->sync_initialized()) <<
@@ -526,14 +481,12 @@
   // visible. If the user exits the signin wizard after this without
   // configuring sync, CloseSyncSetup() will ensure they are logged out.
   configuring_sync_ = false;
-
   DisplayGaiaLoginInNewTabOrWindow();
-  signin_tracker_.reset(new SigninTracker(GetProfile(), this));
 }
 
 void SyncSetupHandler::DisplayGaiaLoginInNewTabOrWindow() {
-  DCHECK(!active_gaia_signin_tab_);
-  GURL url(SyncPromoUI::GetSyncPromoURL(SyncPromoUI::SOURCE_SETTINGS, false));
+  GURL url(SyncPromoUI::GetSyncPromoURL(SyncPromoUI::SOURCE_SETTINGS,
+                                        true));  // auto close after success.
   Browser* browser = chrome::FindBrowserWithWebContents(
       web_ui()->GetWebContents());
   if (!browser) {
@@ -558,10 +511,9 @@
     url = url.ReplaceComponents(replacements);
   }
 
-  active_gaia_signin_tab_ = browser->OpenURL(
+  browser->OpenURL(
       content::OpenURLParams(url, content::Referrer(), SINGLETON_TAB,
                              content::PAGE_TRANSITION_AUTO_BOOKMARK, false));
-  content::WebContentsObserver::Observe(active_gaia_signin_tab_);
 }
 #endif
 
@@ -603,7 +555,6 @@
 // TODO(kochi): Handle error conditions other than timeout.
 // http://crbug.com/128692
 void SyncSetupHandler::DisplayTimeout() {
-  DCHECK(!signin_tracker_);
   // Stop a timer to handle timeout in waiting for checking network connection.
   backend_start_timer_.reset();
 
@@ -616,10 +567,6 @@
       "SyncSetupOverlay.showSyncSetupPage", page, args);
 }
 
-void SyncSetupHandler::RecordSignin() {
-  // By default, do nothing - subclasses can override.
-}
-
 void SyncSetupHandler::OnDidClosePage(const ListValue* args) {
   CloseOverlay();
 }
@@ -643,22 +590,6 @@
   DisplayConfigureSync(true, false);
 }
 
-void SyncSetupHandler::SigninFailed(const GoogleServiceAuthError& error) {
-  DCHECK(!backend_start_timer_);
-
-#if defined(OS_CHROMEOS)
-  // TODO(peria): Show error dialog for prompting sign in and out on
-  // Chrome OS. http://crbug.com/128692
-  CloseOverlay();
-#else
-  last_signin_error_ = error;
-
-  // Don't show the gaia sign in page again since there is no way to show the
-  // user an error message.
-  CloseSyncSetup();
-#endif
-}
-
 Profile* SyncSetupHandler::GetProfile() const {
   return Profile::FromWebUI(web_ui());
 }
@@ -669,27 +600,7 @@
       ProfileSyncServiceFactory::GetForProfile(GetProfile()) : NULL;
 }
 
-void SyncSetupHandler::SigninSuccess() {
-  DCHECK(!backend_start_timer_);
-  ProfileSyncService* service = GetSyncService();
-
-#if !defined(OS_CHROMEOS)
-  CloseGaiaSigninPage();
-#endif
-
-  // If we have signed in while sync is already setup, it must be due to some
-  // kind of re-authentication flow. In that case, just close the signin dialog
-  // rather than forcing the user to go through sync configuration.
-  if (!service || service->HasSyncSetupCompleted()) {
-    RecordSignin();
-    CloseOverlay();
-  } else {
-    DisplayConfigureSync(false, false);
-  }
-}
-
 void SyncSetupHandler::HandleConfigure(const ListValue* args) {
-  DCHECK(!signin_tracker_);
   DCHECK(!sync_startup_tracker_);
   std::string json;
   if (!args->GetString(0, &json)) {
@@ -863,29 +774,18 @@
   // Stop a timer to handle timeout in waiting for checking network connection.
   backend_start_timer_.reset();
 
-  // Clear the signin tracker before canceling sync setup, as it may incorrectly
-  // flag a signin failure.
-  bool was_signing_in = (signin_tracker_.get() != NULL);
-  signin_tracker_.reset();
+  // Clear the sync startup tracker, since the setup wizard is being closed.
   sync_startup_tracker_.reset();
 
-  // TODO(atwilson): Move UMA tracking of signin events out of sync module.
   ProfileSyncService* sync_service = GetSyncService();
   if (IsActiveLogin()) {
     // Don't log a cancel event if the sync setup dialog is being
     // automatically closed due to an auth error.
     if (!sync_service || (!sync_service->HasSyncSetupCompleted() &&
         sync_service->GetAuthError().state() == GoogleServiceAuthError::NONE)) {
-      if (was_signing_in) {
-        // TODO(rsimha): Remove this. Sync should not be logging sign in events.
-        ProfileSyncService::SyncEvent(
-            ProfileSyncService::CANCEL_DURING_SIGNON);
-      } else if (configuring_sync_) {
+      if (configuring_sync_) {
         ProfileSyncService::SyncEvent(
             ProfileSyncService::CANCEL_DURING_CONFIGURE);
-      } else {
-        ProfileSyncService::SyncEvent(
-            ProfileSyncService::CANCEL_FROM_SIGNON_WITHOUT_AUTH);
       }
 
       // If the user clicked "Cancel" while setting up sync, disable sync
@@ -906,11 +806,6 @@
       }
     }
 
-#if !defined(OS_CHROMEOS)
-    // Let the various services know that we're no longer active.
-    CloseGaiaSigninPage();
-#endif
-
     GetLoginUIService()->LoginUIClosed(this);
   }
 
@@ -920,14 +815,6 @@
   if (sync_service)
     sync_service->SetSetupInProgress(false);
 
-#if !defined(OS_CHROMEOS)
-  // Reset the attempted email address and error, otherwise the sync setup
-  // overlay in the settings page will stay in whatever error state it was last
-  // when it is reopened.
-  last_attempted_user_email_.clear();
-  last_signin_error_ = GoogleServiceAuthError::AuthErrorNone();
-#endif
-
   configuring_sync_ = false;
 }
 
@@ -951,20 +838,13 @@
   SigninManagerBase* signin =
       SigninManagerFactory::GetForProfile(GetProfile());
 
-  if (signin->GetAuthenticatedUsername().empty()) {
-    // User is not logged in (cases 1-2). Display login UI.
-    DisplayGaiaLogin();
-    return;
-  }
-
-  if (SigninGlobalError::GetForProfile(GetProfile())->HasMenuItem()) {
-    // Login has been specially requested because previously working credentials
-    // have expired (case 3). Load the sync setup page with a spinner dialog,
-    // and then display the gaia auth page. The user may abandon re-auth by
-    // clicking cancel on the spinner dialog or closing the gaia login tab.
-    StringValue page("spinner");
-    web_ui()->CallJavascriptFunction("SyncSetupOverlay.showSyncSetupPage",
-                                     page);
+  if (signin->GetAuthenticatedUsername().empty() ||
+      SigninGlobalError::GetForProfile(GetProfile())->HasMenuItem()) {
+    // User is not logged in (cases 1-2), or login has been specially requested
+    // because previously working credentials have expired (case 3). Close sync
+    // setup including any visible overlays, and display the gaia auth page.
+    // Control will be returned to the sync settings page once auth is complete.
+    CloseOverlay();
     DisplayGaiaLogin();
     return;
   }
@@ -991,13 +871,6 @@
 
 void SyncSetupHandler::FocusUI() {
   DCHECK(IsActiveLogin());
-#if !defined(OS_CHROMEOS)
-  // Bring the GAIA tab to the foreground if there is one.
-  if (signin_tracker_ && active_gaia_signin_tab_) {
-    BringTabToFront(active_gaia_signin_tab_);
-    return;
-  }
-#endif
   WebContents* web_contents = web_ui()->GetWebContents();
   web_contents->GetDelegate()->ActivateContents(web_contents);
 }
@@ -1007,62 +880,6 @@
   CloseOverlay();
 }
 
-#if !defined(OS_CHROMEOS)
-void SyncSetupHandler::DidStopLoading(
-    content::RenderViewHost* render_view_host) {
-  DCHECK(active_gaia_signin_tab_);
-
-  // If the user lands on a page outside of Gaia, assume they have navigated
-  // away and are no longer thinking about signing in with this tab.  Treat
-  // this as if the user closed the tab. However, don't actually close the tab
-  // since the user is doing something with it.  Disconnect and forget about it
-  // before closing down the sync setup.
-  // The one exception is the expected continue URL.  If the user lands there,
-  // this means sign in was successful.  Ignore the source parameter in the
-  // continue URL since this user may have changed the state of the
-  // "Let me choose what to sync" checkbox.
-  const GURL& url = active_gaia_signin_tab_->GetURL();
-  const GURL continue_url =
-      SyncPromoUI::GetNextPageURLForSyncPromoURL(
-          SyncPromoUI::GetSyncPromoURL(SyncPromoUI::SOURCE_SETTINGS,
-                                       false));
-  GURL::Replacements replacements;
-  replacements.ClearQuery();
-
-  if (!gaia::IsGaiaSignonRealm(url.GetOrigin()) &&
-      url.ReplaceComponents(replacements) !=
-          continue_url.ReplaceComponents(replacements)) {
-    content::WebContentsObserver::Observe(NULL);
-    active_gaia_signin_tab_ = NULL;
-    CloseOverlay();
-  }
-}
-
-void SyncSetupHandler::WebContentsDestroyed(
-    content::WebContents* web_contents) {
-  DCHECK(active_gaia_signin_tab_);
-  CloseOverlay();
-}
-
-// Private member functions.
-
-void SyncSetupHandler::CloseGaiaSigninPage() {
-  if (active_gaia_signin_tab_) {
-    content::WebContentsObserver::Observe(NULL);
-
-    // This can be invoked from a webui handler in the GAIA page (for example,
-    // if the user clicks 'cancel' in the enterprise signin dialog), so
-    // closing this tab in mid-handler can cause crashes. Instead, close it
-    // via a task so we know we aren't in the middle of any webui code.
-    base::MessageLoop::current()->PostTask(
-        FROM_HERE,
-        base::Bind(&CloseTab, base::Unretained(active_gaia_signin_tab_)));
-
-    active_gaia_signin_tab_ = NULL;
-  }
-}
-#endif
-
 bool SyncSetupHandler::FocusExistingWizardIfPresent() {
   LoginUIService* service = GetLoginUIService();
   if (!service->current_login_ui())
diff --git a/chrome/browser/ui/webui/sync_setup_handler.h b/chrome/browser/ui/webui/sync_setup_handler.h
index 26aa049..2f562ac 100644
--- a/chrome/browser/ui/webui/sync_setup_handler.h
+++ b/chrome/browser/ui/webui/sync_setup_handler.h
@@ -8,11 +8,9 @@
 #include "base/gtest_prod_util.h"
 #include "base/memory/scoped_ptr.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"
 #include "chrome/browser/ui/webui/signin/login_ui_service.h"
-#include "content/public/browser/web_contents_observer.h"
 
 class LoginUIService;
 class ProfileManager;
@@ -24,11 +22,7 @@
 }
 
 class SyncSetupHandler : public options::OptionsPageUIHandler,
-                         public SigninTracker::Observer,
                          public SyncStartupTracker::Observer,
-#if !defined(OS_CHROMEOS)
-                         public content::WebContentsObserver,
-#endif
                          public LoginUIService::LoginUI {
  public:
   // Constructs a new SyncSetupHandler. |profile_manager| may be NULL.
@@ -40,10 +34,6 @@
       OVERRIDE;
   virtual void RegisterMessages() OVERRIDE;
 
-  // SigninTracker::Observer implementation.
-  virtual void SigninFailed(const GoogleServiceAuthError& error) OVERRIDE;
-  virtual void SigninSuccess() OVERRIDE;
-
   // SyncStartupTracker::Observer implementation;
   virtual void SyncStartupCompleted() OVERRIDE;
   virtual void SyncStartupFailed() OVERRIDE;
@@ -52,15 +42,6 @@
   virtual void FocusUI() OVERRIDE;
   virtual void CloseUI() OVERRIDE;
 
-#if !defined(OS_CHROMEOS)
-  // No need to track signin windows on chromeos.
-  // content::WebContentsObserver implementation.
-  virtual void DidStopLoading(
-      content::RenderViewHost* render_view_host) OVERRIDE;
-  virtual void WebContentsDestroyed(
-      content::WebContents* web_contents) OVERRIDE;
-#endif
-
   static void GetStaticLocalizedValues(
       base::DictionaryValue* localized_strings,
       content::WebUI* web_ui);
@@ -101,11 +82,6 @@
                            SubmitAuthWithInvalidUsername);
 
   bool is_configuring_sync() const { return configuring_sync_; }
-  bool have_signin_tracker() const { return signin_tracker_; }
-
-  // Overridden by subclasses (like SyncPromoHandler) to log stats about the
-  // user's signin activity.
-  virtual void RecordSignin();
 
   // Display the configure sync UI. If |show_advanced| is true, skip directly
   // to the "advanced settings" dialog, otherwise give the user the simpler
@@ -172,44 +148,14 @@
   // sync setup flow.
   void CloseOverlay();
 
-#if !defined(OS_CHROMEOS)
-  // When using web-flow, closes the Gaia page used to collection user
-  // credentials.
-  void CloseGaiaSigninPage();
-#endif
-
   // Helper object used to wait for the sync backend to startup.
   scoped_ptr<SyncStartupTracker> sync_startup_tracker_;
 
-  // The SigninTracker object used to determine when the user has fully signed
-  // in (this requires waiting for various services to initialize and tracking
-  // errors from multiple sources). Should only be non-null while the login UI
-  // is visible.
-  // TODO(atwilson): Remove references to this on ChromeOS since it will always
-  // be null.
-  scoped_ptr<SigninTracker> signin_tracker_;
-
   // Set to true whenever the sync configure UI is visible. This is used to tell
   // what stage of the setup wizard the user was in and to update the UMA
   // histograms in the case that the user cancels out.
   bool configuring_sync_;
 
-#if !defined(OS_CHROMEOS)
-  // Cache of the last name the client attempted to authenticate.
-  std::string last_attempted_user_email_;
-
-  // The error from the last signin attempt.
-  GoogleServiceAuthError last_signin_error_;
-
-  // When setup starts with login UI, retry login if signing in failed.
-  // When setup starts without login UI, do not retry login and fail.
-  bool retry_on_signin_failure_;
-
-  // When using web-flow, weak pointer to the tab that holds the Gaia sign in
-  // page.
-  content::WebContents* active_gaia_signin_tab_;
-#endif
-
   // Weak reference to the profile manager.
   ProfileManager* const profile_manager_;
 
diff --git a/chrome/browser/ui/webui/sync_setup_handler_unittest.cc b/chrome/browser/ui/webui/sync_setup_handler_unittest.cc
index d0c36e7..cc5379d 100644
--- a/chrome/browser/ui/webui/sync_setup_handler_unittest.cc
+++ b/chrome/browser/ui/webui/sync_setup_handler_unittest.cc
@@ -286,7 +286,6 @@
   virtual Profile* GetProfile() const OVERRIDE { return profile_; }
 
   using SyncSetupHandler::is_configuring_sync;
-  using SyncSetupHandler::have_signin_tracker;
 
  private:
 #if !defined(OS_CHROMEOS)
@@ -430,12 +429,13 @@
   EXPECT_CALL(*mock_pss_, HasSyncSetupCompleted())
       .WillRepeatedly(Return(false));
   handler_->HandleStartSignin(NULL);
-  EXPECT_EQ(handler_.get(),
+
+  // Sync setup hands off control to the gaia login tab.
+  EXPECT_EQ(NULL,
             LoginUIServiceFactory::GetForProfile(
                 profile_.get())->current_login_ui());
 
   ASSERT_FALSE(handler_->is_configuring_sync());
-  ASSERT_TRUE(handler_->have_signin_tracker());
 
   handler_->CloseSyncSetup();
   EXPECT_EQ(NULL,
@@ -567,7 +567,6 @@
       .WillRepeatedly(Return(true));
   SetDefaultExpectationsForConfigPage();
   handler_->OpenSyncSetup();
-  handler_->SigninSuccess();
 
   // It's important to tell sync the user cancelled the setup flow before we
   // tell it we're through with the setup progress.
@@ -638,7 +637,6 @@
   handler_->OpenSyncSetup();
 
   ASSERT_FALSE(handler_->is_configuring_sync());
-  ASSERT_TRUE(handler_->have_signin_tracker());
 }
 
 // TODO(kochi): We need equivalent tests for ChromeOS.
@@ -653,7 +651,6 @@
   handler_->OpenSyncSetup();
 
   ASSERT_FALSE(handler_->is_configuring_sync());
-  ASSERT_TRUE(handler_->have_signin_tracker());
 }
 
 TEST_F(SyncSetupHandlerNonCrosTest, GaiaErrorInitializingSync) {
@@ -667,7 +664,6 @@
   handler_->OpenSyncSetup();
 
   ASSERT_FALSE(handler_->is_configuring_sync());
-  ASSERT_TRUE(handler_->have_signin_tracker());
 }
 
 #endif  // #if !defined(OS_CHROMEOS)
@@ -931,12 +927,12 @@
   // sync backend, and on desktop this displays the login dialog.
   handler_->OpenSyncSetup();
 
-  EXPECT_EQ(handler_.get(),
+  // Sync setup is closed when re-auth is in progress.
+  EXPECT_EQ(NULL,
             LoginUIServiceFactory::GetForProfile(
                 profile_.get())->current_login_ui());
 
   ASSERT_FALSE(handler_->is_configuring_sync());
-  ASSERT_TRUE(handler_->have_signin_tracker());
 #endif
 }
 
diff --git a/chrome/browser/ui/webui/tab_modal_confirm_dialog_webui.cc b/chrome/browser/ui/webui/tab_modal_confirm_dialog_webui.cc
index 8c37a05..d5b8ed9 100644
--- a/chrome/browser/ui/webui/tab_modal_confirm_dialog_webui.cc
+++ b/chrome/browser/ui/webui/tab_modal_confirm_dialog_webui.cc
@@ -17,6 +17,7 @@
 #include "chrome/browser/ui/tab_modal_confirm_dialog_delegate.h"
 #include "chrome/browser/ui/webui/constrained_web_dialog_ui.h"
 #include "chrome/common/url_constants.h"
+#include "components/web_modal/web_contents_modal_dialog_manager.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_ui_data_source.h"
 #include "grit/browser_resources.h"
@@ -28,6 +29,7 @@
 
 using content::WebContents;
 using content::WebUIMessageHandler;
+using web_modal::WebContentsModalDialogManager;
 
 // static
 TabModalConfirmDialog* TabModalConfirmDialog::Create(
@@ -42,7 +44,8 @@
 TabModalConfirmDialogWebUI::TabModalConfirmDialogWebUI(
     TabModalConfirmDialogDelegate* delegate,
     WebContents* web_contents)
-    : delegate_(delegate) {
+    : web_contents_(web_contents),
+      delegate_(delegate) {
   Profile* profile =
       Profile::FromBrowserContext(web_contents->GetBrowserContext());
   content::WebUIDataSource* data_source = content::WebUIDataSource::Create(
@@ -53,7 +56,7 @@
 
   constrained_web_dialog_delegate_ =
       CreateConstrainedWebDialog(profile, this, NULL, web_contents);
-  delegate_->set_close_delegate(this);
+  delegate_->set_operations_delegate(this);
 }
 
 ui::ModalType TabModalConfirmDialogWebUI::GetDialogModalType() const {
@@ -95,7 +98,7 @@
       NOTREACHED() << "Missing or unreadable response from dialog";
   }
 
-  delegate_->set_close_delegate(NULL);
+  delegate_->set_operations_delegate(NULL);
   if (accepted)
     delegate_->Accept();
   else
@@ -120,3 +123,11 @@
 void TabModalConfirmDialogWebUI::CloseDialog() {
   constrained_web_dialog_delegate_->OnDialogCloseFromWebUI();
 }
+
+void TabModalConfirmDialogWebUI::SetPreventCloseOnLoadStart(bool prevent) {
+  web_modal::WebContentsModalDialogManager* web_contents_modal_dialog_manager =
+      WebContentsModalDialogManager::FromWebContents(web_contents_);
+  web_contents_modal_dialog_manager->SetPreventCloseOnLoadStart(
+      constrained_web_dialog_delegate_->GetNativeDialog(),
+      prevent);
+}
diff --git a/chrome/browser/ui/webui/tab_modal_confirm_dialog_webui.h b/chrome/browser/ui/webui/tab_modal_confirm_dialog_webui.h
index c77ac74..592a9f2 100644
--- a/chrome/browser/ui/webui/tab_modal_confirm_dialog_webui.h
+++ b/chrome/browser/ui/webui/tab_modal_confirm_dialog_webui.h
@@ -59,6 +59,9 @@
 
   // TabModalConfirmDialogCloseDelegate:
   virtual void CloseDialog() OVERRIDE;
+  virtual void SetPreventCloseOnLoadStart(bool prevent) OVERRIDE;
+
+  content::WebContents* web_contents_;
 
   scoped_ptr<TabModalConfirmDialogDelegate> delegate_;
 
diff --git a/chrome/browser/ui/webui/translate_internals/translate_internals_handler.h b/chrome/browser/ui/webui/translate_internals/translate_internals_handler.h
index bbb84ce..e6a3444 100644
--- a/chrome/browser/ui/webui/translate_internals/translate_internals_handler.h
+++ b/chrome/browser/ui/webui/translate_internals/translate_internals_handler.h
@@ -9,7 +9,7 @@
 
 #include "chrome/browser/translate/translate_manager.h"
 #include "content/public/browser/web_ui_message_handler.h"
-#include "webkit/plugins/webplugininfo.h"
+#include "content/public/common/webplugininfo.h"
 
 struct LanguageDetectionDetails;
 struct TranslateErrorDetails;
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 d7ebb10..be6c1ee 100644
--- a/chrome/browser/ui/webui/translate_internals/translate_internals_ui.cc
+++ b/chrome/browser/ui/webui/translate_internals/translate_internals_ui.cc
@@ -14,6 +14,7 @@
 #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/translate/language_detection_util.h"
 #include "chrome/common/url_constants.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_ui.h"
@@ -23,10 +24,6 @@
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
 
-#if !defined(OS_IOS)
-#include "third_party/cld/encodings/compact_lang_det/compact_lang_det.h"
-#endif
-
 namespace {
 
 // Sets the languages to |dict|. Each key is a language code and each value is
@@ -69,10 +66,8 @@
       command_line.HasSwitch(switches::kEnableTranslateSettings);
   source->AddBoolean("enable-translate-settings", enable_translate_settings);
 
-#if !defined(OS_IOS)
-  std::string cld_version = CompactLangDet::DetectLanguageVersion();
+  std::string cld_version = LanguageDetectionUtil::GetCLDVersion();
   source->AddString("cld-version", cld_version);
-#endif
 
   return source;
 }
diff --git a/chrome/browser/ui/webui/version_handler.cc b/chrome/browser/ui/webui/version_handler.cc
index d6064fe..065b4f2 100644
--- a/chrome/browser/ui/webui/version_handler.cc
+++ b/chrome/browser/ui/webui/version_handler.cc
@@ -129,9 +129,9 @@
 
 #if defined(ENABLE_PLUGINS)
 void VersionHandler::OnGotPlugins(
-    const std::vector<webkit::WebPluginInfo>& plugins) {
+    const std::vector<content::WebPluginInfo>& plugins) {
   // Obtain the version of the first enabled Flash plugin.
-  std::vector<webkit::WebPluginInfo> info_array;
+  std::vector<content::WebPluginInfo> info_array;
   content::PluginService::GetInstance()->GetPluginInfoArray(
       GURL(), kFlashPluginSwfMimeType, false, &info_array, NULL);
   string16 flash_version =
diff --git a/chrome/browser/ui/webui/version_handler.h b/chrome/browser/ui/webui/version_handler.h
index a8f5b11..2fc65d4 100644
--- a/chrome/browser/ui/webui/version_handler.h
+++ b/chrome/browser/ui/webui/version_handler.h
@@ -10,7 +10,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/values.h"
 #include "content/public/browser/web_ui_message_handler.h"
-#include "webkit/plugins/webplugininfo.h"
+#include "content/public/common/webplugininfo.h"
 
 // Handler class for Version page operations.
 class VersionHandler : public content::WebUIMessageHandler {
@@ -34,7 +34,7 @@
 
   // Callback for GetPlugins which responds to the page with the Flash version.
   // This also initiates the OS Version load on ChromeOS.
-  void OnGotPlugins(const std::vector<webkit::WebPluginInfo>& plugins);
+  void OnGotPlugins(const std::vector<content::WebPluginInfo>& plugins);
 
   // Factory for the creating refs in callbacks.
   base::WeakPtrFactory<VersionHandler> weak_ptr_factory_;
diff --git a/chrome/browser/ui/window_sizer/window_sizer_ash.cc b/chrome/browser/ui/window_sizer/window_sizer_ash.cc
index d954240..254d047 100644
--- a/chrome/browser/ui/window_sizer/window_sizer_ash.cc
+++ b/chrome/browser/ui/window_sizer/window_sizer_ash.cc
@@ -23,9 +23,9 @@
 
 namespace {
 
-// When a window gets opened in default mode and the screen is less then this
-// width, the window will get opened in maximized mode. This value can be
-// reduced to a "tame" number if the feature is disabled.
+// When a window gets opened in default mode and the screen is less than or
+// equal to this width, the window will get opened in maximized mode. This value
+// can be reduced to a "tame" number if the feature is disabled.
 const int kForceMaximizeWidthLimit = 1366;
 const int kForceMaximizeWidthLimitDisabled = 640;
 
@@ -212,7 +212,7 @@
       // When using "small screens" we want to always open in full screen mode.
       if (passed_show_state == ui::SHOW_STATE_DEFAULT &&
           !browser_->is_session_restore() &&
-          work_area.width() < GetForceMaximizedWidthLimit() &&
+          work_area.width() <= GetForceMaximizedWidthLimit() &&
           (!browser_->window() || !browser_->window()->IsFullscreen()) &&
           (!browser_->fullscreen_controller() ||
            !browser_->fullscreen_controller()->IsFullscreenForBrowser()))
diff --git a/chrome/browser/ui/window_sizer/window_sizer_ash_unittest.cc b/chrome/browser/ui/window_sizer/window_sizer_ash_unittest.cc
index fbe3d57..2790756 100644
--- a/chrome/browser/ui/window_sizer/window_sizer_ash_unittest.cc
+++ b/chrome/browser/ui/window_sizer/window_sizer_ash_unittest.cc
@@ -102,7 +102,8 @@
 WindowSizerTestWithBrowser::~WindowSizerTestWithBrowser() {
 }
 
-}
+}  // namespace
+
 // Test that the window is sized appropriately for the first run experience
 // where the default window bounds calculation is invoked.
 TEST_F(WindowSizerTest, DefaultSizeCase) {
@@ -584,45 +585,64 @@
   scoped_ptr<Browser> browser(
       chrome::CreateBrowserWithTestWindowForParams(&native_params));
 
+  // A common screen size for Chrome OS devices where this behavior is
+  // desirable.
+  const gfx::Rect p1366x768(0, 0, 1366, 768);
+
   // If there is no previous state the window should get maximized if the
-  // screen is smaller than our limit (1350 pixels width).
+  // screen is less than or equal to our limit (1366 pixels width).
   gfx::Rect window_bounds;
   ui::WindowShowState out_show_state1 = ui::SHOW_STATE_DEFAULT;
   GetWindowBoundsAndShowState(
-                  p1024x768,                    // The screen resolution.
-                  p1024x768,                    // The monitor work area.
-                  gfx::Rect(),                  // The second monitor.
-                  gfx::Rect(),                  // The (persisted) bounds.
-                  p1024x768,                    // The overall work area.
-                  ui::SHOW_STATE_NORMAL,        // The persisted show state.
-                  ui::SHOW_STATE_DEFAULT,       // The last show state.
-                  DEFAULT,                      // No persisted values.
-                  browser.get(),                // Use this browser.
-                  gfx::Rect(),                  // Don't request valid bounds.
-                  &window_bounds,
-                  &out_show_state1);
+      p1366x768,                    // The screen resolution.
+      p1366x768,                    // The monitor work area.
+      gfx::Rect(),                  // The second monitor.
+      gfx::Rect(),                  // The (persisted) bounds.
+      p1366x768,                    // The overall work area.
+      ui::SHOW_STATE_NORMAL,        // The persisted show state.
+      ui::SHOW_STATE_DEFAULT,       // The last show state.
+      DEFAULT,                      // No persisted values.
+      browser.get(),                // Use this browser.
+      gfx::Rect(),                  // Don't request valid bounds.
+      &window_bounds,
+      &out_show_state1);
   EXPECT_EQ(ui::SHOW_STATE_MAXIMIZED, out_show_state1);
 
   // If there is a stored coordinate however, that should be taken instead.
   ui::WindowShowState out_show_state2 = ui::SHOW_STATE_DEFAULT;
   GetWindowBoundsAndShowState(
-                  p1024x768,                    // The screen resolution.
-                  p1024x768,                    // The monitor work area.
-                  gfx::Rect(),                  // The second monitor.
-                  gfx::Rect(50, 100, 300, 150), // The (persisted) bounds.
-                  p1024x768,                    // The overall work area.
-                  ui::SHOW_STATE_NORMAL,        // The persisted show state.
-                  ui::SHOW_STATE_DEFAULT,       // The last show state.
-                  PERSISTED,                    // Set the persisted values.
-                  browser.get(),                // Use this browser.
-                  gfx::Rect(),                  // Don't request valid bounds.
-                  &window_bounds,
-                  &out_show_state2);
+      p1366x768,                    // The screen resolution.
+      p1366x768,                    // The monitor work area.
+      gfx::Rect(),                  // The second monitor.
+      gfx::Rect(50, 100, 300, 150), // The (persisted) bounds.
+      p1366x768,                    // The overall work area.
+      ui::SHOW_STATE_NORMAL,        // The persisted show state.
+      ui::SHOW_STATE_DEFAULT,       // The last show state.
+      PERSISTED,                    // Set the persisted values.
+      browser.get(),                // Use this browser.
+      gfx::Rect(),                  // Don't request valid bounds.
+      &window_bounds,
+      &out_show_state2);
   EXPECT_EQ(ui::SHOW_STATE_NORMAL, out_show_state2);
   EXPECT_EQ("50,100 300x150", window_bounds.ToString());
 
- }
-
+  // A larger monitor should not trigger auto-maximize.
+  ui::WindowShowState out_show_state3 = ui::SHOW_STATE_DEFAULT;
+  GetWindowBoundsAndShowState(
+      p1600x1200,                   // The screen resolution.
+      p1600x1200,                   // The monitor work area.
+      gfx::Rect(),                  // The second monitor.
+      gfx::Rect(),                  // The (persisted) bounds.
+      p1600x1200,                   // The overall work area.
+      ui::SHOW_STATE_NORMAL,        // The persisted show state.
+      ui::SHOW_STATE_DEFAULT,       // The last show state.
+      DEFAULT,                      // No persisted values.
+      browser.get(),                // Use this browser.
+      gfx::Rect(),                  // Don't request valid bounds.
+      &window_bounds,
+      &out_show_state3);
+  EXPECT_EQ(ui::SHOW_STATE_DEFAULT, out_show_state3);
+}
 
 #if defined(OS_CHROMEOS)
 #define MAYBE_PlaceNewWindowsOnMultipleDisplays PlaceNewWindowsOnMultipleDisplays
diff --git a/chrome/browser/upload_list.cc b/chrome/browser/upload_list.cc
deleted file mode 100644
index 3f618aa..0000000
--- a/chrome/browser/upload_list.cc
+++ /dev/null
@@ -1,95 +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/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 (base::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
deleted file mode 100644
index 23c4ff5..0000000
--- a/chrome/browser/upload_list.h
+++ /dev/null
@@ -1,88 +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_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
deleted file mode 100644
index 153f9db..0000000
--- a/chrome/browser/upload_list_unittest.cc
+++ /dev/null
@@ -1,44 +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 <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/web_resource/promo_resource_service_unittest.cc b/chrome/browser/web_resource/promo_resource_service_unittest.cc
index 95e2a77..0f0ae62 100644
--- a/chrome/browser/web_resource/promo_resource_service_unittest.cc
+++ b/chrome/browser/web_resource/promo_resource_service_unittest.cc
@@ -27,7 +27,7 @@
 #include "content/public/browser/notification_service.h"
 #include "net/url_request/test_url_fetcher_factory.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/icu/public/i18n/unicode/smpdtfmt.h"
+#include "third_party/icu/source/i18n/unicode/smpdtfmt.h"
 
 namespace {