Fix attempt for the double-SessionRestoreImpl problem.

The problem is that BrowserInit::ProcessCommandLineAlreadyRunning gets called too
early, before launching the first profile during normal startup.

BUG=111238
TEST=NONE

Committed: http://src.chromium.org/viewvc/chrome?view=rev&revision=122065

Review URL: https://chromiumcodereview.appspot.com/9365049

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@123209 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome/browser/process_singleton_win.cc b/chrome/browser/process_singleton_win.cc
index 4d20415..fc55aac 100644
--- a/chrome/browser/process_singleton_win.cc
+++ b/chrome/browser/process_singleton_win.cc
@@ -57,6 +57,66 @@
   return singleton->WndProc(hwnd, message, wparam, lparam);
 }
 
+bool ParseCommandLine(const COPYDATASTRUCT* cds,
+                      CommandLine* parsed_command_line,
+                      FilePath* current_directory) {
+  // We should have enough room for the shortest command (min_message_size)
+  // and also be a multiple of wchar_t bytes. The shortest command
+  // possible is L"START\0\0" (empty current directory and command line).
+  static const int min_message_size = 7;
+  if (cds->cbData < min_message_size * sizeof(wchar_t) ||
+      cds->cbData % sizeof(wchar_t) != 0) {
+    LOG(WARNING) << "Invalid WM_COPYDATA, length = " << cds->cbData;
+    return false;
+  }
+
+  // We split the string into 4 parts on NULLs.
+  DCHECK(cds->lpData);
+  const std::wstring msg(static_cast<wchar_t*>(cds->lpData),
+                         cds->cbData / sizeof(wchar_t));
+  const std::wstring::size_type first_null = msg.find_first_of(L'\0');
+  if (first_null == 0 || first_null == std::wstring::npos) {
+    // no NULL byte, don't know what to do
+    LOG(WARNING) << "Invalid WM_COPYDATA, length = " << msg.length() <<
+      ", first null = " << first_null;
+    return false;
+  }
+
+  // Decode the command, which is everything until the first NULL.
+  if (msg.substr(0, first_null) == L"START") {
+    // Another instance is starting parse the command line & do what it would
+    // have done.
+    VLOG(1) << "Handling STARTUP request from another process";
+    const std::wstring::size_type second_null =
+        msg.find_first_of(L'\0', first_null + 1);
+    if (second_null == std::wstring::npos ||
+        first_null == msg.length() - 1 || second_null == msg.length()) {
+      LOG(WARNING) << "Invalid format for start command, we need a string in 4 "
+        "parts separated by NULLs";
+      return false;
+    }
+
+    // Get current directory.
+    *current_directory = FilePath(msg.substr(first_null + 1,
+                                             second_null - first_null));
+
+    const std::wstring::size_type third_null =
+        msg.find_first_of(L'\0', second_null + 1);
+    if (third_null == std::wstring::npos ||
+        third_null == msg.length()) {
+      LOG(WARNING) << "Invalid format for start command, we need a string in 4 "
+        "parts separated by NULLs";
+    }
+
+    // Get command line.
+    const std::wstring cmd_line =
+        msg.substr(second_null + 1, third_null - second_null);
+    *parsed_command_line = CommandLine::FromString(cmd_line);
+    return true;
+  }
+  return false;
+}
+
 }  // namespace
 
 // Microsoft's Softricity virtualization breaks the sandbox processes.
@@ -268,8 +328,17 @@
     NOTIMPLEMENTED();
 #else
     // Attempt to place ourselves in the foreground / flash the task bar.
-    if (IsWindow(foreground_window_))
+    if (foreground_window_ != NULL && IsWindow(foreground_window_)) {
       SetForegroundWindow(foreground_window_);
+    } else {
+      // Read the command line and store it. It will be replayed when the
+      // ProcessSingleton becomes unlocked.
+      CommandLine parsed_command_line(CommandLine::NO_PROGRAM);
+      FilePath current_directory;
+      if (ParseCommandLine(cds, &parsed_command_line, &current_directory))
+        saved_startup_messages_.push_back(
+            std::make_pair(parsed_command_line.argv(), current_directory));
+    }
 #endif
     return TRUE;
   }
@@ -280,88 +349,11 @@
     return FALSE;
   }
 
-  // We should have enough room for the shortest command (min_message_size)
-  // and also be a multiple of wchar_t bytes. The shortest command
-  // possible is L"START\0\0" (empty current directory and command line).
-  static const int min_message_size = 7;
-  if (cds->cbData < min_message_size * sizeof(wchar_t) ||
-      cds->cbData % sizeof(wchar_t) != 0) {
-    LOG(WARNING) << "Invalid WM_COPYDATA, length = " << cds->cbData;
+  CommandLine parsed_command_line(CommandLine::NO_PROGRAM);
+  FilePath current_directory;
+  if (!ParseCommandLine(cds, &parsed_command_line, &current_directory))
     return TRUE;
-  }
-
-  // We split the string into 4 parts on NULLs.
-  DCHECK(cds->lpData);
-  const std::wstring msg(static_cast<wchar_t*>(cds->lpData),
-                         cds->cbData / sizeof(wchar_t));
-  const std::wstring::size_type first_null = msg.find_first_of(L'\0');
-  if (first_null == 0 || first_null == std::wstring::npos) {
-    // no NULL byte, don't know what to do
-    LOG(WARNING) << "Invalid WM_COPYDATA, length = " << msg.length() <<
-      ", first null = " << first_null;
-    return TRUE;
-  }
-
-  // Decode the command, which is everything until the first NULL.
-  if (msg.substr(0, first_null) == L"START") {
-    // Another instance is starting parse the command line & do what it would
-    // have done.
-    VLOG(1) << "Handling STARTUP request from another process";
-    const std::wstring::size_type second_null =
-      msg.find_first_of(L'\0', first_null + 1);
-    if (second_null == std::wstring::npos ||
-        first_null == msg.length() - 1 || second_null == msg.length()) {
-      LOG(WARNING) << "Invalid format for start command, we need a string in 4 "
-        "parts separated by NULLs";
-      return TRUE;
-    }
-
-    // Get current directory.
-    const FilePath cur_dir(msg.substr(first_null + 1,
-                                      second_null - first_null));
-
-    const std::wstring::size_type third_null =
-        msg.find_first_of(L'\0', second_null + 1);
-    if (third_null == std::wstring::npos ||
-        third_null == msg.length()) {
-      LOG(WARNING) << "Invalid format for start command, we need a string in 4 "
-        "parts separated by NULLs";
-    }
-
-    // Get command line.
-    const std::wstring cmd_line =
-      msg.substr(second_null + 1, third_null - second_null);
-
-    CommandLine parsed_command_line = CommandLine::FromString(cmd_line);
-    PrefService* prefs = g_browser_process->local_state();
-    DCHECK(prefs);
-
-    // Handle the --uninstall-extension startup action. This needs to done here
-    // in the process that is running with the target profile, otherwise the
-    // uninstall will fail to unload and remove all components.
-    if (parsed_command_line.HasSwitch(switches::kUninstallExtension)) {
-      // The uninstall extension switch can't be combined with the profile
-      // directory switch.
-      DCHECK(!parsed_command_line.HasSwitch(switches::kProfileDirectory));
-
-      Profile* profile = ProfileManager::GetLastUsedProfile();
-      if (!profile) {
-        // We should only be able to get here if the profile already exists and
-        // has been created.
-        NOTREACHED();
-        return TRUE;
-      }
-
-      ExtensionsStartupUtil ext_startup_util;
-      ext_startup_util.UninstallExtension(parsed_command_line, profile);
-      return TRUE;
-    }
-
-    // Run the browser startup sequence again, with the command line of the
-    // signalling process.
-    BrowserInit::ProcessCommandLineAlreadyRunning(parsed_command_line, cur_dir);
-    return TRUE;
-  }
+  ProcessCommandLine(parsed_command_line, current_directory);
   return TRUE;
 }
 
@@ -377,3 +369,35 @@
 
   return ::DefWindowProc(hwnd, message, wparam, lparam);
 }
+
+void ProcessSingleton::ProcessCommandLine(const CommandLine& command_line,
+                                          const FilePath& current_directory) {
+  PrefService* prefs = g_browser_process->local_state();
+  DCHECK(prefs);
+
+  // Handle the --uninstall-extension startup action. This needs to done here
+  // in the process that is running with the target profile, otherwise the
+  // uninstall will fail to unload and remove all components.
+  if (command_line.HasSwitch(switches::kUninstallExtension)) {
+    // The uninstall extension switch can't be combined with the profile
+    // directory switch.
+    DCHECK(!command_line.HasSwitch(switches::kProfileDirectory));
+
+    Profile* profile = ProfileManager::GetLastUsedProfile();
+    if (!profile) {
+      // We should only be able to get here if the profile already exists and
+      // has been created.
+      NOTREACHED();
+      return;
+    }
+
+    ExtensionsStartupUtil ext_startup_util;
+    ext_startup_util.UninstallExtension(command_line, profile);
+    return;
+  }
+
+  // Run the browser startup sequence again, with the command line of the
+  // signalling process.
+  BrowserInit::ProcessCommandLineAlreadyRunning(command_line,
+                                                current_directory);
+}