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