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