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