startup_browser_creator.cc revision f2477e01787aa58f445919b809d89e252beef54f
1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/ui/startup/startup_browser_creator.h"
6
7#include <algorithm>   // For max().
8#include <set>
9
10#include "apps/app_load_service.h"
11#include "apps/switches.h"
12#include "base/bind.h"
13#include "base/bind_helpers.h"
14#include "base/command_line.h"
15#include "base/compiler_specific.h"
16#include "base/environment.h"
17#include "base/file_util.h"
18#include "base/files/file_path.h"
19#include "base/lazy_instance.h"
20#include "base/logging.h"
21#include "base/memory/scoped_ptr.h"
22#include "base/metrics/histogram.h"
23#include "base/metrics/statistics_recorder.h"
24#include "base/path_service.h"
25#include "base/prefs/pref_service.h"
26#include "base/strings/string_number_conversions.h"
27#include "base/strings/string_split.h"
28#include "base/strings/utf_string_conversions.h"
29#include "base/threading/thread_restrictions.h"
30#include "chrome/browser/app_mode/app_mode_utils.h"
31#include "chrome/browser/auto_launch_trial.h"
32#include "chrome/browser/automation/automation_provider.h"
33#include "chrome/browser/automation/automation_provider_list.h"
34#include "chrome/browser/automation/testing_automation_provider.h"
35#include "chrome/browser/browser_process.h"
36#include "chrome/browser/chrome_notification_types.h"
37#include "chrome/browser/custom_handlers/protocol_handler_registry.h"
38#include "chrome/browser/extensions/startup_helper.h"
39#include "chrome/browser/extensions/unpacked_installer.h"
40#include "chrome/browser/first_run/first_run.h"
41#include "chrome/browser/google/google_util.h"
42#include "chrome/browser/notifications/desktop_notification_service.h"
43#include "chrome/browser/prefs/incognito_mode_prefs.h"
44#include "chrome/browser/prefs/session_startup_pref.h"
45#include "chrome/browser/profiles/profile.h"
46#include "chrome/browser/profiles/profile_manager.h"
47#include "chrome/browser/profiles/profiles_state.h"
48#include "chrome/browser/search_engines/util.h"
49#include "chrome/browser/ui/browser.h"
50#include "chrome/browser/ui/browser_dialogs.h"
51#include "chrome/browser/ui/browser_finder.h"
52#include "chrome/browser/ui/browser_window.h"
53#include "chrome/browser/ui/startup/startup_browser_creator_impl.h"
54#include "chrome/common/chrome_constants.h"
55#include "chrome/common/chrome_paths.h"
56#include "chrome/common/chrome_result_codes.h"
57#include "chrome/common/chrome_switches.h"
58#include "chrome/common/chrome_version_info.h"
59#include "chrome/common/net/url_fixer_upper.h"
60#include "chrome/common/pref_names.h"
61#include "chrome/common/url_constants.h"
62#include "chrome/installer/util/browser_distribution.h"
63#include "content/public/browser/browser_thread.h"
64#include "content/public/browser/child_process_security_policy.h"
65#include "content/public/browser/navigation_controller.h"
66#include "grit/locale_settings.h"
67#include "net/base/net_util.h"
68#include "ui/base/l10n/l10n_util.h"
69#include "ui/base/resource/resource_bundle.h"
70
71#if defined(OS_CHROMEOS)
72#include "chrome/browser/chromeos/app_mode/app_launch_utils.h"
73#include "chrome/browser/chromeos/kiosk_mode/kiosk_mode_settings.h"
74#include "chrome/browser/chromeos/login/user_manager.h"
75#include "chrome/browser/chromeos/profiles/profile_helper.h"
76#include "chromeos/chromeos_switches.h"
77#endif
78
79#if defined(TOOLKIT_VIEWS) && defined(OS_LINUX)
80#include "ui/events/x/touch_factory_x11.h"
81#endif
82
83#if defined(OS_WIN)
84#include "chrome/browser/automation/chrome_frame_automation_provider_win.h"
85#include "chrome/browser/ui/startup/startup_browser_creator_win.h"
86#endif
87
88#if defined(ENABLE_FULL_PRINTING)
89#include "chrome/browser/printing/cloud_print/cloud_print_proxy_service.h"
90#include "chrome/browser/printing/cloud_print/cloud_print_proxy_service_factory.h"
91#include "chrome/browser/printing/print_dialog_cloud.h"
92#endif
93
94using content::BrowserThread;
95using content::ChildProcessSecurityPolicy;
96
97namespace {
98
99// Keeps track on which profiles have been launched.
100class ProfileLaunchObserver : public content::NotificationObserver {
101 public:
102  ProfileLaunchObserver()
103      : profile_to_activate_(NULL),
104        activated_profile_(false) {
105    registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED,
106                   content::NotificationService::AllSources());
107    registrar_.Add(this, chrome::NOTIFICATION_BROWSER_WINDOW_READY,
108                   content::NotificationService::AllSources());
109  }
110  virtual ~ProfileLaunchObserver() {}
111
112  virtual void Observe(int type,
113                       const content::NotificationSource& source,
114                       const content::NotificationDetails& details) OVERRIDE {
115    switch (type) {
116      case chrome::NOTIFICATION_PROFILE_DESTROYED: {
117        Profile* profile = content::Source<Profile>(source).ptr();
118        launched_profiles_.erase(profile);
119        opened_profiles_.erase(profile);
120        if (profile == profile_to_activate_)
121          profile_to_activate_ = NULL;
122        // If this profile was the last launched one without an opened window,
123        // then we may be ready to activate |profile_to_activate_|.
124        MaybeActivateProfile();
125        break;
126      }
127      case chrome::NOTIFICATION_BROWSER_WINDOW_READY: {
128        Browser* browser = content::Source<Browser>(source).ptr();
129        DCHECK(browser);
130        opened_profiles_.insert(browser->profile());
131        MaybeActivateProfile();
132        break;
133      }
134      default:
135        NOTREACHED();
136    }
137  }
138
139  bool HasBeenLaunched(const Profile* profile) const {
140    return launched_profiles_.find(profile) != launched_profiles_.end();
141  }
142
143  void AddLaunched(Profile* profile) {
144    launched_profiles_.insert(profile);
145    // Since the startup code only executes for browsers launched in
146    // desktop mode, i.e., HOST_DESKTOP_TYPE_NATIVE. Ash should never get here.
147    if (chrome::FindBrowserWithProfile(profile,
148                                       chrome::HOST_DESKTOP_TYPE_NATIVE)) {
149      // A browser may get opened before we get initialized (e.g., in tests),
150      // so we never see the NOTIFICATION_BROWSER_WINDOW_READY for it.
151      opened_profiles_.insert(profile);
152    }
153  }
154
155  void Clear() {
156    launched_profiles_.clear();
157    opened_profiles_.clear();
158  }
159
160  bool activated_profile() { return activated_profile_; }
161
162  void set_profile_to_activate(Profile* profile) {
163    profile_to_activate_ = profile;
164    MaybeActivateProfile();
165  }
166
167 private:
168  void MaybeActivateProfile() {
169    if (!profile_to_activate_)
170      return;
171    // Check that browsers have been opened for all the launched profiles.
172    // Note that browsers opened for profiles that were not added as launched
173    // profiles are simply ignored.
174    std::set<const Profile*>::const_iterator i = launched_profiles_.begin();
175    for (; i != launched_profiles_.end(); ++i) {
176      if (opened_profiles_.find(*i) == opened_profiles_.end())
177        return;
178    }
179    // Asynchronous post to give a chance to the last window to completely
180    // open and activate before trying to activate |profile_to_activate_|.
181    BrowserThread::PostTask(
182        BrowserThread::UI, FROM_HERE,
183        base::Bind(&ProfileLaunchObserver::ActivateProfile,
184                   base::Unretained(this)));
185    // Avoid posting more than once before ActivateProfile gets called.
186    registrar_.Remove(this, chrome::NOTIFICATION_BROWSER_WINDOW_READY,
187                      content::NotificationService::AllSources());
188    registrar_.Remove(this, chrome::NOTIFICATION_PROFILE_DESTROYED,
189                      content::NotificationService::AllSources());
190  }
191
192  void ActivateProfile() {
193    // We need to test again, in case the profile got deleted in the mean time.
194    if (profile_to_activate_) {
195      Browser* browser = chrome::FindBrowserWithProfile(
196          profile_to_activate_, chrome::HOST_DESKTOP_TYPE_NATIVE);
197      // |profile| may never get launched, e.g., if it only had
198      // incognito Windows and one of them was used to exit Chrome.
199      // So it won't have a browser in that case.
200      if (browser)
201        browser->window()->Activate();
202      // No need try to activate this profile again.
203      profile_to_activate_ = NULL;
204    }
205    // Assign true here, even if no browser was actually activated, so that
206    // the test can stop waiting, and fail gracefully when needed.
207    activated_profile_ = true;
208  }
209
210  // These are the profiles that get launched by
211  // StartupBrowserCreator::LaunchBrowser.
212  std::set<const Profile*> launched_profiles_;
213  // These are the profiles for which at least one browser window has been
214  // opened. This is needed to know when it is safe to activate
215  // |profile_to_activate_|, otherwise, new browser windows being opened will
216  // be activated on top of it.
217  std::set<const Profile*> opened_profiles_;
218  content::NotificationRegistrar registrar_;
219  // This is NULL until the profile to activate has been chosen. This value,
220  // should only be set once all profiles have been launched, otherwise,
221  // activation may not happen after the launch of newer profiles.
222  Profile* profile_to_activate_;
223  // Set once we attempted to activate a profile. We only get one shot at this.
224  bool activated_profile_;
225
226  DISALLOW_COPY_AND_ASSIGN(ProfileLaunchObserver);
227};
228
229base::LazyInstance<ProfileLaunchObserver> profile_launch_observer =
230    LAZY_INSTANCE_INITIALIZER;
231
232// Dumps the current set of the browser process's histograms to |output_file|.
233// The file is overwritten if it exists. This function should only be called in
234// the blocking pool.
235void DumpBrowserHistograms(const base::FilePath& output_file) {
236  base::ThreadRestrictions::AssertIOAllowed();
237
238  std::string output_string(base::StatisticsRecorder::ToJSON(std::string()));
239  file_util::WriteFile(output_file, output_string.data(),
240                       static_cast<int>(output_string.size()));
241}
242
243}  // namespace
244
245StartupBrowserCreator::StartupBrowserCreator()
246    : is_default_browser_dialog_suppressed_(false),
247      show_main_browser_window_(true) {
248}
249
250StartupBrowserCreator::~StartupBrowserCreator() {}
251
252// static
253bool StartupBrowserCreator::was_restarted_read_ = false;
254
255// static
256bool StartupBrowserCreator::in_synchronous_profile_launch_ = false;
257
258void StartupBrowserCreator::AddFirstRunTab(const GURL& url) {
259  first_run_tabs_.push_back(url);
260}
261
262// static
263bool StartupBrowserCreator::InSynchronousProfileLaunch() {
264  return in_synchronous_profile_launch_;
265}
266
267bool StartupBrowserCreator::LaunchBrowser(
268    const CommandLine& command_line,
269    Profile* profile,
270    const base::FilePath& cur_dir,
271    chrome::startup::IsProcessStartup process_startup,
272    chrome::startup::IsFirstRun is_first_run,
273    int* return_code) {
274
275  in_synchronous_profile_launch_ =
276      process_startup == chrome::startup::IS_PROCESS_STARTUP;
277  DCHECK(profile);
278
279  // Continue with the incognito profile from here on if Incognito mode
280  // is forced.
281  if (IncognitoModePrefs::ShouldLaunchIncognito(command_line,
282                                                profile->GetPrefs())) {
283    profile = profile->GetOffTheRecordProfile();
284  } else if (command_line.HasSwitch(switches::kIncognito)) {
285    LOG(WARNING) << "Incognito mode disabled by policy, launching a normal "
286                 << "browser session.";
287  }
288
289  // Note: This check should have been done in ProcessCmdLineImpl()
290  // before calling this function. However chromeos/login/login_utils.cc
291  // calls this function directly (see comments there) so it has to be checked
292  // again.
293  const bool silent_launch = command_line.HasSwitch(switches::kSilentLaunch);
294
295  if (!silent_launch) {
296    StartupBrowserCreatorImpl lwp(cur_dir, command_line, this, is_first_run);
297    const std::vector<GURL> urls_to_launch =
298        GetURLsFromCommandLine(command_line, cur_dir, profile);
299    const bool launched = lwp.Launch(profile, urls_to_launch,
300                               in_synchronous_profile_launch_,
301                               chrome::HOST_DESKTOP_TYPE_NATIVE);
302    in_synchronous_profile_launch_ = false;
303    if (!launched) {
304      LOG(ERROR) << "launch error";
305      if (return_code)
306        *return_code = chrome::RESULT_CODE_INVALID_CMDLINE_URL;
307      return false;
308    }
309  } else {
310    in_synchronous_profile_launch_ = false;
311  }
312
313  profile_launch_observer.Get().AddLaunched(profile);
314
315#if defined(OS_CHROMEOS)
316  g_browser_process->platform_part()->profile_helper()->ProfileStartup(
317      profile,
318      process_startup);
319#endif
320  return true;
321}
322
323// static
324bool StartupBrowserCreator::WasRestarted() {
325  // Stores the value of the preference kWasRestarted had when it was read.
326  static bool was_restarted = false;
327
328  if (!was_restarted_read_) {
329    PrefService* pref_service = g_browser_process->local_state();
330    was_restarted = pref_service->GetBoolean(prefs::kWasRestarted);
331    pref_service->SetBoolean(prefs::kWasRestarted, false);
332    was_restarted_read_ = true;
333  }
334  return was_restarted;
335}
336
337// static
338SessionStartupPref StartupBrowserCreator::GetSessionStartupPref(
339    const CommandLine& command_line,
340    Profile* profile) {
341  DCHECK(profile);
342  PrefService* prefs = profile->GetPrefs();
343  SessionStartupPref pref = SessionStartupPref::GetStartupPref(prefs);
344
345  // IsChromeFirstRun() looks for a sentinel file to determine whether the user
346  // is starting Chrome for the first time. On Chrome OS, the sentinel is stored
347  // in a location shared by all users and the check is meaningless. Query the
348  // UserManager instead to determine whether the user is new.
349#if defined(OS_CHROMEOS)
350  const bool is_first_run = chromeos::UserManager::Get()->IsCurrentUserNew();
351#else
352  const bool is_first_run = first_run::IsChromeFirstRun();
353#endif
354
355  // The pref has an OS-dependent default value. For the first run only, this
356  // default is overridden with SessionStartupPref::DEFAULT so that first run
357  // behavior (sync promo, welcome page) is consistently invoked.
358  // This applies only if the pref is still at its default and has not been
359  // set by the user, managed prefs or policy.
360  if (is_first_run && SessionStartupPref::TypeIsDefault(prefs))
361    pref.type = SessionStartupPref::DEFAULT;
362
363  // The switches::kRestoreLastSession command line switch is used to restore
364  // sessions after a browser self restart (e.g. after a Chrome upgrade).
365  // However, new profiles can be created from a browser process that has this
366  // switch so do not set the session pref to SessionStartupPref::LAST for
367  // those as there is nothing to restore.
368  if ((command_line.HasSwitch(switches::kRestoreLastSession) ||
369       StartupBrowserCreator::WasRestarted()) &&
370      !profile->IsNewProfile()) {
371    pref.type = SessionStartupPref::LAST;
372  }
373  if (pref.type == SessionStartupPref::LAST &&
374      IncognitoModePrefs::ShouldLaunchIncognito(command_line, prefs)) {
375    // We don't store session information when incognito. If the user has
376    // chosen to restore last session and launched incognito, fallback to
377    // default launch behavior.
378    pref.type = SessionStartupPref::DEFAULT;
379  }
380
381  return pref;
382}
383
384// static
385void StartupBrowserCreator::ClearLaunchedProfilesForTesting() {
386  profile_launch_observer.Get().Clear();
387}
388
389// static
390std::vector<GURL> StartupBrowserCreator::GetURLsFromCommandLine(
391    const CommandLine& command_line,
392    const base::FilePath& cur_dir,
393    Profile* profile) {
394  std::vector<GURL> urls;
395
396  const CommandLine::StringVector& params = command_line.GetArgs();
397  for (size_t i = 0; i < params.size(); ++i) {
398    base::FilePath param = base::FilePath(params[i]);
399    // Handle Vista way of searching - "? <search-term>"
400    if ((param.value().size() > 2) && (param.value()[0] == '?') &&
401        (param.value()[1] == ' ')) {
402      GURL url(GetDefaultSearchURLForSearchTerms(
403          profile, param.LossyDisplayName().substr(2)));
404      if (url.is_valid()) {
405        urls.push_back(url);
406        continue;
407      }
408    }
409
410    // Otherwise, fall through to treating it as a URL.
411
412    // This will create a file URL or a regular URL.
413    // This call can (in rare circumstances) block the UI thread.
414    // Allow it until this bug is fixed.
415    //  http://code.google.com/p/chromium/issues/detail?id=60641
416    GURL url;
417    {
418      base::ThreadRestrictions::ScopedAllowIO allow_io;
419      url = URLFixerUpper::FixupRelativeFile(cur_dir, param);
420    }
421    // Exclude dangerous schemes.
422    if (url.is_valid()) {
423      ChildProcessSecurityPolicy* policy =
424          ChildProcessSecurityPolicy::GetInstance();
425      if (policy->IsWebSafeScheme(url.scheme()) ||
426          url.SchemeIs(chrome::kFileScheme) ||
427#if defined(OS_CHROMEOS)
428          // In ChromeOS, allow a settings page to be specified on the
429          // command line. See ExistingUserController::OnLoginSuccess.
430          (url.spec().find(chrome::kChromeUISettingsURL) == 0) ||
431#endif
432          (url.spec().compare(content::kAboutBlankURL) == 0)) {
433        urls.push_back(url);
434      }
435    }
436  }
437#if defined(OS_WIN)
438  if (urls.empty()) {
439    // If we are in Windows 8 metro mode and were launched as a result of the
440    // search charm or via a url navigation in metro, then fetch the
441    // corresponding url.
442    GURL url(chrome::GetURLToOpen(profile));
443    if (url.is_valid())
444      urls.push_back(url);
445  }
446#endif  // OS_WIN
447  return urls;
448}
449
450// static
451bool StartupBrowserCreator::ProcessCmdLineImpl(
452    const CommandLine& command_line,
453    const base::FilePath& cur_dir,
454    bool process_startup,
455    Profile* last_used_profile,
456    const Profiles& last_opened_profiles,
457    int* return_code,
458    StartupBrowserCreator* browser_creator) {
459  DCHECK(last_used_profile);
460  if (process_startup) {
461    if (command_line.HasSwitch(switches::kDisablePromptOnRepost))
462      content::NavigationController::DisablePromptOnRepost();
463  }
464
465  bool silent_launch = false;
466
467#if defined(ENABLE_AUTOMATION)
468  // Look for the testing channel ID ONLY during process startup
469  if (process_startup &&
470      command_line.HasSwitch(switches::kTestingChannelID)) {
471    std::string testing_channel_id = command_line.GetSwitchValueASCII(
472        switches::kTestingChannelID);
473    // TODO(sanjeevr) Check if we need to make this a singleton for
474    // compatibility with the old testing code
475    // If there are any extra parameters, we expect each one to generate a
476    // new tab; if there are none then we get one homepage tab.
477    int expected_tab_count = 1;
478    if (command_line.HasSwitch(switches::kNoStartupWindow) &&
479        !command_line.HasSwitch(switches::kAutoLaunchAtStartup)) {
480      expected_tab_count = 0;
481#if defined(OS_CHROMEOS)
482    // kLoginManager will cause Chrome to start up with the ChromeOS login
483    // screen instead of a browser window, so it won't load any tabs.
484    } else if (command_line.HasSwitch(chromeos::switches::kLoginManager)) {
485      expected_tab_count = 0;
486#endif
487    } else if (command_line.HasSwitch(switches::kRestoreLastSession)) {
488      std::string restore_session_value(
489          command_line.GetSwitchValueASCII(switches::kRestoreLastSession));
490      base::StringToInt(restore_session_value, &expected_tab_count);
491    } else {
492      std::vector<GURL> urls_to_open = GetURLsFromCommandLine(
493          command_line, cur_dir, last_used_profile);
494      expected_tab_count =
495          std::max(1, static_cast<int>(urls_to_open.size()));
496    }
497    if (!CreateAutomationProvider<TestingAutomationProvider>(
498        testing_channel_id,
499        last_used_profile,
500        static_cast<size_t>(expected_tab_count)))
501      return false;
502  }
503
504  if (command_line.HasSwitch(switches::kSilentLaunch)) {
505    std::vector<GURL> urls_to_open = GetURLsFromCommandLine(
506        command_line, cur_dir, last_used_profile);
507    size_t expected_tabs =
508        std::max(static_cast<int>(urls_to_open.size()), 0);
509    if (expected_tabs == 0)
510      silent_launch = true;
511  }
512
513  if (command_line.HasSwitch(switches::kAutomationClientChannelID)) {
514    std::string automation_channel_id = command_line.GetSwitchValueASCII(
515        switches::kAutomationClientChannelID);
516    // If there are any extra parameters, we expect each one to generate a
517    // new tab; if there are none then we have no tabs
518    std::vector<GURL> urls_to_open = GetURLsFromCommandLine(
519        command_line, cur_dir, last_used_profile);
520    size_t expected_tabs =
521        std::max(static_cast<int>(urls_to_open.size()), 0);
522    if (expected_tabs == 0)
523      silent_launch = true;
524
525    if (command_line.HasSwitch(switches::kChromeFrame)) {
526#if defined(OS_WIN)
527      if (!CreateAutomationProvider<ChromeFrameAutomationProvider>(
528          automation_channel_id, last_used_profile, expected_tabs))
529        return false;
530#endif
531    } else {
532      if (!CreateAutomationProvider<AutomationProvider>(
533          automation_channel_id, last_used_profile, expected_tabs))
534        return false;
535    }
536  }
537#endif  // defined(ENABLE_AUTOMATION)
538
539#if defined(ENABLE_FULL_PRINTING)
540  // If we are just displaying a print dialog we shouldn't open browser
541  // windows.
542  if (command_line.HasSwitch(switches::kCloudPrintFile) &&
543      print_dialog_cloud::CreatePrintDialogFromCommandLine(command_line)) {
544    silent_launch = true;
545  }
546
547  // If we are checking the proxy enabled policy, don't open any windows.
548  if (command_line.HasSwitch(switches::kCheckCloudPrintConnectorPolicy)) {
549    silent_launch = true;
550    if (CloudPrintProxyServiceFactory::GetForProfile(last_used_profile)->
551        EnforceCloudPrintConnectorPolicyAndQuit())
552      // Success, nothing more needs to be done, so return false to stop
553      // launching and quit.
554      return false;
555  }
556#endif  // defined(ENABLE_FULL_PRINTING)
557
558  if (command_line.HasSwitch(switches::kExplicitlyAllowedPorts)) {
559    std::string allowed_ports =
560        command_line.GetSwitchValueASCII(switches::kExplicitlyAllowedPorts);
561    net::SetExplicitlyAllowedPorts(allowed_ports);
562  }
563
564  if (command_line.HasSwitch(switches::kInstallFromWebstore)) {
565    extensions::StartupHelper helper;
566    helper.InstallFromWebstore(command_line, last_used_profile);
567    // Nothing more needs to be done, so return false to stop launching and
568    // quit.
569    return false;
570  }
571
572  if (command_line.HasSwitch(switches::kValidateCrx)) {
573    if (!process_startup) {
574      LOG(ERROR) << "chrome is already running; you must close all running "
575                 << "instances before running with the --"
576                 << switches::kValidateCrx << " flag";
577      return false;
578    }
579    extensions::StartupHelper helper;
580    std::string message;
581    std::string error;
582    if (helper.ValidateCrx(command_line, &error))
583      message = std::string("ValidateCrx Success");
584    else
585      message = std::string("ValidateCrx Failure: ") + error;
586    printf("%s\n", message.c_str());
587    return false;
588  }
589
590  if (command_line.HasSwitch(switches::kLimitedInstallFromWebstore)) {
591    extensions::StartupHelper helper;
592    helper.LimitedInstallFromWebstore(command_line, last_used_profile,
593                                      base::Bind(&base::DoNothing));
594  }
595
596#if defined(OS_CHROMEOS)
597  // The browser will be launched after the user logs in.
598  if (command_line.HasSwitch(chromeos::switches::kLoginManager) ||
599      command_line.HasSwitch(chromeos::switches::kLoginPassword)) {
600    silent_launch = true;
601  }
602
603  if (chrome::IsRunningInAppMode() &&
604      command_line.HasSwitch(switches::kAppId)) {
605    chromeos::LaunchAppOrDie(
606        last_used_profile,
607        command_line.GetSwitchValueASCII(switches::kAppId));
608
609    // Skip browser launch since app mode launches its app window.
610    silent_launch = true;
611  }
612#endif
613
614#if defined(TOOLKIT_VIEWS) && defined(USE_X11)
615  ui::TouchFactory::SetTouchDeviceListFromCommandLine();
616#endif
617
618  if (!process_startup &&
619      command_line.HasSwitch(switches::kDumpBrowserHistograms)) {
620    // Only handle --dump-browser-histograms from a rendezvous. In this case, do
621    // not open a new browser window even if no output file was given.
622    base::FilePath output_file(
623        command_line.GetSwitchValuePath(switches::kDumpBrowserHistograms));
624    if (!output_file.empty()) {
625      BrowserThread::PostBlockingPoolTask(
626          FROM_HERE,
627          base::Bind(&DumpBrowserHistograms, output_file));
628    }
629    silent_launch = true;
630  }
631
632  // If we don't want to launch a new browser window or tab (in the case
633  // of an automation request), we are done here.
634  if (silent_launch)
635    return true;
636
637  // Check for --load-and-launch-app.
638  if (command_line.HasSwitch(apps::kLoadAndLaunchApp) &&
639      !IncognitoModePrefs::ShouldLaunchIncognito(
640          command_line, last_used_profile->GetPrefs())) {
641    CommandLine::StringType path = command_line.GetSwitchValueNative(
642        apps::kLoadAndLaunchApp);
643
644    if (!apps::AppLoadService::Get(last_used_profile)->LoadAndLaunch(
645            base::FilePath(path), command_line, cur_dir)) {
646      return false;
647    }
648
649    // Return early here since we don't want to open a browser window.
650    // The exception is when there are no browser windows, since we don't want
651    // chrome to shut down.
652    // TODO(jackhou): Do this properly once keep-alive is handled by the
653    // background page of apps. Tracked at http://crbug.com/175381
654    if (chrome::GetTotalBrowserCountForProfile(last_used_profile) != 0)
655      return true;
656  }
657
658  chrome::startup::IsProcessStartup is_process_startup = process_startup ?
659      chrome::startup::IS_PROCESS_STARTUP :
660      chrome::startup::IS_NOT_PROCESS_STARTUP;
661  chrome::startup::IsFirstRun is_first_run = first_run::IsChromeFirstRun() ?
662      chrome::startup::IS_FIRST_RUN : chrome::startup::IS_NOT_FIRST_RUN;
663  // |last_opened_profiles| will be empty in the following circumstances:
664  // - This is the first launch. |last_used_profile| is the initial profile.
665  // - The user exited the browser by closing all windows for all
666  // profiles. |last_used_profile| is the profile which owned the last open
667  // window.
668  // - Only incognito windows were open when the browser exited.
669  // |last_used_profile| is the last used incognito profile. Restoring it will
670  // create a browser window for the corresponding original profile.
671  if (last_opened_profiles.empty()) {
672    // If the last used profile was a guest, show the user manager instead.
673    if (profiles::IsNewProfileManagementEnabled() &&
674        last_used_profile->IsGuestSession()) {
675      chrome::ShowUserManager(base::FilePath());
676      return true;
677    }
678    if (!browser_creator->LaunchBrowser(command_line, last_used_profile,
679                                        cur_dir, is_process_startup,
680                                        is_first_run, return_code)) {
681      return false;
682    }
683  } else {
684    // Launch the last used profile with the full command line, and the other
685    // opened profiles without the URLs to launch.
686    CommandLine command_line_without_urls(command_line.GetProgram());
687    const CommandLine::SwitchMap& switches = command_line.GetSwitches();
688    for (CommandLine::SwitchMap::const_iterator switch_it = switches.begin();
689         switch_it != switches.end(); ++switch_it) {
690      command_line_without_urls.AppendSwitchNative(switch_it->first,
691                                                   switch_it->second);
692    }
693    // Launch the profiles in the order they became active.
694    for (Profiles::const_iterator it = last_opened_profiles.begin();
695         it != last_opened_profiles.end(); ++it) {
696      // Don't launch additional profiles which would only open a new tab
697      // page. When restarting after an update, all profiles will reopen last
698      // open pages.
699      SessionStartupPref startup_pref =
700          GetSessionStartupPref(command_line, *it);
701      if (*it != last_used_profile &&
702          startup_pref.type == SessionStartupPref::DEFAULT &&
703          !HasPendingUncleanExit(*it))
704        continue;
705
706      // Don't re-open a browser window for the guest profile.
707      if (profiles::IsNewProfileManagementEnabled() &&
708          (*it)->IsGuestSession())
709        continue;
710
711      if (!browser_creator->LaunchBrowser((*it == last_used_profile) ?
712          command_line : command_line_without_urls, *it, cur_dir,
713          is_process_startup, is_first_run, return_code))
714        return false;
715      // We've launched at least one browser.
716      is_process_startup = chrome::startup::IS_NOT_PROCESS_STARTUP;
717    }
718    // This must be done after all profiles have been launched so the observer
719    // knows about all profiles to wait for before activating this one.
720
721    // If the last used profile was the guest one, we didn't open it so
722    // we don't need to activate it either.
723    if (!profiles::IsNewProfileManagementEnabled() &&
724        !last_used_profile->IsGuestSession())
725      profile_launch_observer.Get().set_profile_to_activate(last_used_profile);
726  }
727  return true;
728}
729
730template <class AutomationProviderClass>
731bool StartupBrowserCreator::CreateAutomationProvider(
732    const std::string& channel_id,
733    Profile* profile,
734    size_t expected_tabs) {
735#if defined(ENABLE_AUTOMATION)
736  scoped_refptr<AutomationProviderClass> automation =
737      new AutomationProviderClass(profile);
738  if (!automation->InitializeChannel(channel_id))
739    return false;
740  automation->SetExpectedTabCount(expected_tabs);
741
742  AutomationProviderList* list = g_browser_process->GetAutomationProviderList();
743  DCHECK(list);
744  list->AddProvider(automation.get());
745#endif  // defined(ENABLE_AUTOMATION)
746
747  return true;
748}
749
750// static
751void StartupBrowserCreator::ProcessCommandLineOnProfileCreated(
752    const CommandLine& command_line,
753    const base::FilePath& cur_dir,
754    Profile* profile,
755    Profile::CreateStatus status) {
756  if (status == Profile::CREATE_STATUS_INITIALIZED)
757    ProcessCmdLineImpl(command_line, cur_dir, false, profile, Profiles(), NULL,
758                       NULL);
759}
760
761// static
762void StartupBrowserCreator::ProcessCommandLineAlreadyRunning(
763    const CommandLine& command_line,
764    const base::FilePath& cur_dir,
765    const base::FilePath& profile_path) {
766  ProfileManager* profile_manager = g_browser_process->profile_manager();
767  Profile* profile = profile_manager->GetProfileByPath(profile_path);
768
769  // The profile isn't loaded yet and so needs to be loaded asynchronously.
770  if (!profile) {
771    profile_manager->CreateProfileAsync(profile_path,
772        base::Bind(&StartupBrowserCreator::ProcessCommandLineOnProfileCreated,
773                   command_line, cur_dir), string16(), string16(),
774                   std::string());
775    return;
776  }
777
778  ProcessCmdLineImpl(command_line, cur_dir, false, profile, Profiles(), NULL,
779                     NULL);
780}
781
782// static
783bool StartupBrowserCreator::ActivatedProfile() {
784  return profile_launch_observer.Get().activated_profile();
785}
786
787bool HasPendingUncleanExit(Profile* profile) {
788  return profile->GetLastSessionExitType() == Profile::EXIT_CRASHED &&
789      !profile_launch_observer.Get().HasBeenLaunched(profile);
790}
791