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