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