Boot prefetch optimization for Chrome Frame (experimental)

If chrome is warmed up during a single reboot, it gets paged
in for subsequent reboots and the cold startup times essentially
look like warm times thereafter! The 'warm up' is done by
setting up a 'RunOnce' key during DLLRegisterServer of 
npchrome_frame.dll.

This works because chrome prefetch becomes part of boot
prefetch file ntosboot-b00dfaad.pf and paged in on subsequent
reboots. As long as the sytem does not undergo significant 
memory pressure those pages remain in memory and we get pretty
amazing startup times, down to about 300 ms from 1200 ms

The downside is:
- Whether chrome frame is used or not, there's a read penalty
  (1200-300 =) 900 ms for every boot.
- Heavy system memory usage after reboot will nullify the benefits
  but the user will still pay the cost.
- Overall the time saved will always be less than total time spent
  paging in chrome
- We are not sure when the chrome 'warm up' will age out from the
  boot prefetch file.

The idea here is to try this out on chrome frame dev channel
and see if it produces a significant drift in startup numbers.


Review URL: http://codereview.chromium.org/2936010

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@52489 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome_frame/chrome_tab.cc b/chrome_frame/chrome_tab.cc
index 5165d2c..71c20ff 100644
--- a/chrome_frame/chrome_tab.cc
+++ b/chrome_frame/chrome_tab.cc
@@ -23,6 +23,8 @@
 #include "base/sys_string_conversions.h"
 #include "base/win_util.h"
 #include "chrome/common/chrome_constants.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/installer/util/google_update_settings.h"
 #include "grit/chrome_frame_resources.h"
 #include "chrome_frame/bho.h"
 #include "chrome_frame/chrome_active_document.h"
@@ -60,6 +62,9 @@
 const wchar_t kProtocolHandlers[] =
     L"Software\\Classes\\Protocols\\Handler";
 
+const wchar_t kRunOnce[] =
+    L"Software\\Microsoft\\Windows\\CurrentVersion\\RunOnce";
+
 const wchar_t kBhoNoLoadExplorerValue[] = L"NoExplorer";
 
 // {0562BFC3-2550-45b4-BD8E-A310583D3A6F}
@@ -206,31 +211,6 @@
 #pragma managed(pop)
 #endif
 
-const wchar_t kPostPlatformUAKey[] =
-    L"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\"
-    L"User Agent\\Post Platform";
-const wchar_t kClockUserAgent[] = L"chromeframe";
-
-// To delete the clock user agent, set value to NULL.
-// TODO(tommi): Remove this method when it's no longer used.
-HRESULT SetClockUserAgent(const wchar_t* value) {
-  HRESULT hr;
-  RegKey ua_key;
-  if (ua_key.Create(HKEY_LOCAL_MACHINE, kPostPlatformUAKey, KEY_WRITE)) {
-    if (value) {
-      ua_key.WriteValue(kClockUserAgent, value);
-    } else {
-      ua_key.DeleteValue(kClockUserAgent);
-    }
-    hr = S_OK;
-  } else {
-    DLOG(ERROR) << __FUNCTION__ << ": " << kPostPlatformUAKey;
-    hr = E_UNEXPECTED;
-  }
-
-  return hr;
-}
-
 HRESULT RefreshElevationPolicy() {
   const wchar_t kIEFrameDll[] = L"ieframe.dll";
   const char kIERefreshPolicy[] = "IERefreshElevationPolicy";
@@ -292,9 +272,6 @@
 }
 
 HRESULT UnregisterChromeTabBHO() {
-  // TODO(tommi): remove this in future versions.
-  SetClockUserAgent(NULL);
-
   RegKey ie_bho_key;
   if (!ie_bho_key.Open(HKEY_LOCAL_MACHINE, kBhoRegistryPath,
                        KEY_READ | KEY_WRITE)) {
@@ -320,21 +297,49 @@
   return S_OK;
 }
 
-HRESULT CleanupCFProtocol() {
-  RegKey protocol_handlers_key;
-  if (protocol_handlers_key.Open(HKEY_LOCAL_MACHINE, kProtocolHandlers,
-                                 KEY_READ | KEY_WRITE)) {
-    RegKey cf_protocol_key;
-    if (cf_protocol_key.Open(protocol_handlers_key.Handle(), L"cf",
-                             KEY_QUERY_VALUE)) {
-      std::wstring protocol_clsid_string;
-      if (cf_protocol_key.ReadValue(L"CLSID", &protocol_clsid_string)) {
-        CLSID protocol_clsid = {0};
-        IIDFromString(protocol_clsid_string.c_str(), &protocol_clsid);
-        if (IsEqualGUID(protocol_clsid, CLSID_ChromeProtocol))
-          protocol_handlers_key.DeleteKey(L"cf");
-      }
-    }
+// Experimental boot prefetch optimization for Chrome Frame
+//
+// If chrome is warmed up during a single reboot, it gets paged
+// in for subsequent reboots and the cold startup times essentially
+// look like warm times thereafter! The 'warm up' is done by
+// setting up a 'RunOnce' key during DLLRegisterServer of
+// npchrome_frame.dll.
+//
+// This works because chrome prefetch becomes part of boot
+// prefetch file ntosboot-b00dfaad.pf and paged in on subsequent
+// reboots. As long as the sytem does not undergo significant
+// memory pressure those pages remain in memory and we get pretty
+// amazing startup times, down to about 300 ms from 1200 ms
+//
+// The downside is:
+// - Whether chrome frame is used or not, there's a read penalty
+//  (1200-300 =) 900 ms for every boot.
+// - Heavy system memory usage after reboot will nullify the benefits
+//  but the user will still pay the cost.
+// - Overall the time saved will always be less than total time spent
+//  paging in chrome
+// - We are not sure when the chrome 'warm up' will age out from the
+//  boot prefetch file.
+//
+// The idea here is to try this out on chrome frame dev channel
+// and see if it produces a significant drift in startup numbers.
+HRESULT SetupRunOnce() {
+  if (win_util::GetWinVersion() >= win_util::WINVERSION_VISTA)
+    return S_OK;
+
+  std::wstring channel_name;
+  if (!GoogleUpdateSettings::GetChromeChannel(true, &channel_name) ||
+      (0 != lstrcmpiW(L"dev", channel_name.c_str()))) {
+    return S_OK;
+  }
+
+  RegKey run_once;
+  if (run_once.Create(HKEY_CURRENT_USER, kRunOnce, KEY_READ | KEY_WRITE)) {
+    CommandLine run_once_command(chrome_launcher::GetChromeExecutablePath());
+    run_once_command.AppendSwitchWithValue(
+        switches::kAutomationClientChannelID, L"0");
+    run_once_command.AppendSwitch(switches::kChromeFrame);
+    run_once.WriteValue(L"A", run_once_command.command_line_string().c_str());
   }
 
   return S_OK;
@@ -369,6 +374,7 @@
     RegisterChromeTabBHO();
     if (!RegisterSecuredMimeHandler(true))
       hr = E_FAIL;
+    SetupRunOnce();
   }
 
   if (UtilIsPersistentNPAPIMarkerSet()) {
@@ -395,8 +401,6 @@
     hr = _AtlModule.UpdateRegistryFromResourceS(IDR_CHROMEFRAME_NPAPI, FALSE);
   }
 
-  // TODO(joshia): Remove after 2 refresh releases
-  CleanupCFProtocol();
   return hr;
 }