• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 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/browser_init.h"
6 
7 #include <algorithm>   // For max().
8 
9 #include "base/compiler_specific.h"
10 #include "base/environment.h"
11 #include "base/event_recorder.h"
12 #include "base/file_path.h"
13 #include "base/memory/scoped_ptr.h"
14 #include "base/metrics/histogram.h"
15 #include "base/path_service.h"
16 #include "base/string_number_conversions.h"
17 #include "base/string_split.h"
18 #include "base/threading/thread_restrictions.h"
19 #include "base/utf_string_conversions.h"
20 #include "chrome/browser/automation/automation_provider.h"
21 #include "chrome/browser/automation/automation_provider_list.h"
22 #include "chrome/browser/automation/chrome_frame_automation_provider.h"
23 #include "chrome/browser/automation/testing_automation_provider.h"
24 #include "chrome/browser/browser_process.h"
25 #include "chrome/browser/defaults.h"
26 #include "chrome/browser/extensions/extension_creator.h"
27 #include "chrome/browser/extensions/extension_service.h"
28 #include "chrome/browser/extensions/pack_extension_job.h"
29 #include "chrome/browser/first_run/first_run.h"
30 #include "chrome/browser/net/predictor_api.h"
31 #include "chrome/browser/net/url_fixer_upper.h"
32 #include "chrome/browser/notifications/desktop_notification_service.h"
33 #include "chrome/browser/platform_util.h"
34 #include "chrome/browser/prefs/pref_service.h"
35 #include "chrome/browser/prefs/session_startup_pref.h"
36 #include "chrome/browser/printing/cloud_print/cloud_print_proxy_service.h"
37 #include "chrome/browser/printing/print_dialog_cloud.h"
38 #include "chrome/browser/profiles/profile.h"
39 #include "chrome/browser/search_engines/template_url.h"
40 #include "chrome/browser/search_engines/template_url_model.h"
41 #include "chrome/browser/sessions/session_restore.h"
42 #include "chrome/browser/sessions/session_service.h"
43 #include "chrome/browser/shell_integration.h"
44 #include "chrome/browser/tab_contents/link_infobar_delegate.h"
45 #include "chrome/browser/tab_contents/simple_alert_infobar_delegate.h"
46 #include "chrome/browser/tabs/pinned_tab_codec.h"
47 #include "chrome/browser/tabs/tab_strip_model.h"
48 #include "chrome/browser/ui/browser_list.h"
49 #include "chrome/browser/ui/browser_navigator.h"
50 #include "chrome/browser/ui/browser_window.h"
51 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
52 #include "chrome/common/chrome_constants.h"
53 #include "chrome/common/chrome_paths.h"
54 #include "chrome/common/chrome_switches.h"
55 #include "chrome/common/extensions/extension_constants.h"
56 #include "chrome/common/pref_names.h"
57 #include "chrome/common/url_constants.h"
58 #include "chrome/installer/util/browser_distribution.h"
59 #include "content/browser/browser_thread.h"
60 #include "content/browser/child_process_security_policy.h"
61 #include "content/browser/renderer_host/render_process_host.h"
62 #include "content/browser/tab_contents/navigation_controller.h"
63 #include "content/browser/tab_contents/tab_contents.h"
64 #include "content/browser/tab_contents/tab_contents_view.h"
65 #include "content/common/result_codes.h"
66 #include "grit/chromium_strings.h"
67 #include "grit/generated_resources.h"
68 #include "grit/locale_settings.h"
69 #include "grit/theme_resources.h"
70 #include "net/base/net_util.h"
71 #include "net/url_request/url_request.h"
72 #include "ui/base/l10n/l10n_util.h"
73 #include "ui/base/resource/resource_bundle.h"
74 #include "webkit/glue/webkit_glue.h"
75 
76 #if defined(OS_MACOSX)
77 #include "chrome/browser/ui/cocoa/keystone_infobar.h"
78 #endif
79 
80 #if defined(TOOLKIT_USES_GTK)
81 #include "chrome/browser/ui/gtk/gtk_util.h"
82 #endif
83 
84 #if defined(OS_CHROMEOS)
85 #include "chrome/browser/chromeos/cros/cros_library.h"
86 #include "chrome/browser/chromeos/cros/mount_library.h"
87 #include "chrome/browser/chromeos/cros/network_library.h"
88 #include "chrome/browser/chromeos/customization_document.h"
89 #include "chrome/browser/chromeos/enterprise_extension_observer.h"
90 #include "chrome/browser/chromeos/gview_request_interceptor.h"
91 #include "chrome/browser/chromeos/low_battery_observer.h"
92 #include "chrome/browser/chromeos/network_message_observer.h"
93 #include "chrome/browser/chromeos/network_state_notifier.h"
94 #include "chrome/browser/chromeos/sms_observer.h"
95 #include "chrome/browser/chromeos/update_observer.h"
96 #include "chrome/browser/chromeos/wm_message_listener.h"
97 #include "chrome/browser/chromeos/wm_overview_controller.h"
98 #include "chrome/browser/ui/webui/mediaplayer_ui.h"
99 #endif
100 
101 #if defined(HAVE_XINPUT2)
102 #include "views/focus/accelerator_handler.h"
103 #endif
104 
105 namespace {
106 
107 // SetAsDefaultBrowserTask ----------------------------------------------------
108 
109 class SetAsDefaultBrowserTask : public Task {
110  public:
111   SetAsDefaultBrowserTask();
112   virtual ~SetAsDefaultBrowserTask();
113 
114  private:
115   virtual void Run();
116 
117   DISALLOW_COPY_AND_ASSIGN(SetAsDefaultBrowserTask);
118 };
119 
SetAsDefaultBrowserTask()120 SetAsDefaultBrowserTask::SetAsDefaultBrowserTask() {
121 }
122 
~SetAsDefaultBrowserTask()123 SetAsDefaultBrowserTask::~SetAsDefaultBrowserTask() {
124 }
125 
Run()126 void SetAsDefaultBrowserTask::Run() {
127   ShellIntegration::SetAsDefaultBrowser();
128 }
129 
130 
131 // DefaultBrowserInfoBarDelegate ----------------------------------------------
132 
133 // The delegate for the infobar shown when Chrome is not the default browser.
134 class DefaultBrowserInfoBarDelegate : public ConfirmInfoBarDelegate {
135  public:
136   explicit DefaultBrowserInfoBarDelegate(TabContents* contents);
137 
138  private:
139   virtual ~DefaultBrowserInfoBarDelegate();
140 
AllowExpiry()141   void AllowExpiry() { should_expire_ = true; }
142 
143   // ConfirmInfoBarDelegate:
144   virtual bool ShouldExpire(
145       const NavigationController::LoadCommittedDetails& details) const OVERRIDE;
146   virtual void InfoBarClosed() OVERRIDE;
147   virtual SkBitmap* GetIcon() const OVERRIDE;
148   virtual string16 GetMessageText() const OVERRIDE;
149   virtual string16 GetButtonLabel(InfoBarButton button) const OVERRIDE;
150   virtual bool NeedElevation(InfoBarButton button) const OVERRIDE;
151   virtual bool Accept() OVERRIDE;
152   virtual bool Cancel() OVERRIDE;
153 
154   // The Profile that we restore sessions from.
155   Profile* profile_;
156 
157   // Whether the user clicked one of the buttons.
158   bool action_taken_;
159 
160   // Whether the info-bar should be dismissed on the next navigation.
161   bool should_expire_;
162 
163   // Used to delay the expiration of the info-bar.
164   ScopedRunnableMethodFactory<DefaultBrowserInfoBarDelegate> method_factory_;
165 
166   DISALLOW_COPY_AND_ASSIGN(DefaultBrowserInfoBarDelegate);
167 };
168 
DefaultBrowserInfoBarDelegate(TabContents * contents)169 DefaultBrowserInfoBarDelegate::DefaultBrowserInfoBarDelegate(
170     TabContents* contents)
171     : ConfirmInfoBarDelegate(contents),
172       profile_(contents->profile()),
173       action_taken_(false),
174       should_expire_(false),
175       ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {
176   // We want the info-bar to stick-around for few seconds and then be hidden
177   // on the next navigation after that.
178   MessageLoop::current()->PostDelayedTask(FROM_HERE,
179       method_factory_.NewRunnableMethod(
180           &DefaultBrowserInfoBarDelegate::AllowExpiry), 8000);  // 8 seconds.
181 }
182 
~DefaultBrowserInfoBarDelegate()183 DefaultBrowserInfoBarDelegate::~DefaultBrowserInfoBarDelegate() {
184 }
185 
ShouldExpire(const NavigationController::LoadCommittedDetails & details) const186 bool DefaultBrowserInfoBarDelegate::ShouldExpire(
187     const NavigationController::LoadCommittedDetails& details) const {
188   return should_expire_;
189 }
190 
InfoBarClosed()191 void DefaultBrowserInfoBarDelegate::InfoBarClosed() {
192   if (!action_taken_)
193     UMA_HISTOGRAM_COUNTS("DefaultBrowserWarning.Ignored", 1);
194   delete this;
195 }
196 
GetIcon() const197 SkBitmap* DefaultBrowserInfoBarDelegate::GetIcon() const {
198   return ResourceBundle::GetSharedInstance().GetBitmapNamed(
199      IDR_PRODUCT_ICON_32);
200 }
201 
GetMessageText() const202 string16 DefaultBrowserInfoBarDelegate::GetMessageText() const {
203   return l10n_util::GetStringUTF16(IDS_DEFAULT_BROWSER_INFOBAR_SHORT_TEXT);
204 }
205 
GetButtonLabel(InfoBarButton button) const206 string16 DefaultBrowserInfoBarDelegate::GetButtonLabel(
207     InfoBarButton button) const {
208   return l10n_util::GetStringUTF16((button == BUTTON_OK) ?
209       IDS_SET_AS_DEFAULT_INFOBAR_BUTTON_LABEL :
210       IDS_DONT_ASK_AGAIN_INFOBAR_BUTTON_LABEL);
211 }
212 
NeedElevation(InfoBarButton button) const213 bool DefaultBrowserInfoBarDelegate::NeedElevation(InfoBarButton button) const {
214   return button == BUTTON_OK;
215 }
216 
Accept()217 bool DefaultBrowserInfoBarDelegate::Accept() {
218   action_taken_ = true;
219   UMA_HISTOGRAM_COUNTS("DefaultBrowserWarning.SetAsDefault", 1);
220   g_browser_process->file_thread()->message_loop()->PostTask(FROM_HERE,
221       new SetAsDefaultBrowserTask());
222   return true;
223 }
224 
Cancel()225 bool DefaultBrowserInfoBarDelegate::Cancel() {
226   action_taken_ = true;
227   UMA_HISTOGRAM_COUNTS("DefaultBrowserWarning.DontSetAsDefault", 1);
228   // User clicked "Don't ask me again", remember that.
229   profile_->GetPrefs()->SetBoolean(prefs::kCheckDefaultBrowser, false);
230   return true;
231 }
232 
233 
234 // NotifyNotDefaultBrowserTask ------------------------------------------------
235 
236 class NotifyNotDefaultBrowserTask : public Task {
237  public:
238   NotifyNotDefaultBrowserTask();
239   virtual ~NotifyNotDefaultBrowserTask();
240 
241  private:
242   virtual void Run();
243 
244   DISALLOW_COPY_AND_ASSIGN(NotifyNotDefaultBrowserTask);
245 };
246 
NotifyNotDefaultBrowserTask()247 NotifyNotDefaultBrowserTask::NotifyNotDefaultBrowserTask() {
248 }
249 
~NotifyNotDefaultBrowserTask()250 NotifyNotDefaultBrowserTask::~NotifyNotDefaultBrowserTask() {
251 }
252 
Run()253 void NotifyNotDefaultBrowserTask::Run() {
254   Browser* browser = BrowserList::GetLastActive();
255   if (!browser)
256     return;  // Reached during ui tests.
257   // Don't show the info-bar if there are already info-bars showing.
258   // In ChromeBot tests, there might be a race. This line appears to get
259   // called during shutdown and |tab| can be NULL.
260   TabContents* tab = browser->GetSelectedTabContents();
261   if (!tab || tab->infobar_count() > 0)
262     return;
263   tab->AddInfoBar(new DefaultBrowserInfoBarDelegate(tab));
264 }
265 
266 
267 // CheckDefaultBrowserTask ----------------------------------------------------
268 
269 class CheckDefaultBrowserTask : public Task {
270  public:
271   CheckDefaultBrowserTask();
272   virtual ~CheckDefaultBrowserTask();
273 
274  private:
275   virtual void Run();
276 
277   DISALLOW_COPY_AND_ASSIGN(CheckDefaultBrowserTask);
278 };
279 
CheckDefaultBrowserTask()280 CheckDefaultBrowserTask::CheckDefaultBrowserTask() {
281 }
282 
~CheckDefaultBrowserTask()283 CheckDefaultBrowserTask::~CheckDefaultBrowserTask() {
284 }
285 
Run()286 void CheckDefaultBrowserTask::Run() {
287   if (ShellIntegration::IsDefaultBrowser() ||
288       !platform_util::CanSetAsDefaultBrowser()) {
289     return;
290   }
291   BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
292                           new NotifyNotDefaultBrowserTask());
293 }
294 
295 
296 // SessionCrashedInfoBarDelegate ----------------------------------------------
297 
298 // A delegate for the InfoBar shown when the previous session has crashed.
299 class SessionCrashedInfoBarDelegate : public ConfirmInfoBarDelegate {
300  public:
301   explicit SessionCrashedInfoBarDelegate(TabContents* contents);
302 
303  private:
304   virtual ~SessionCrashedInfoBarDelegate();
305 
306   // ConfirmInfoBarDelegate:
307   virtual void InfoBarClosed() OVERRIDE;
308   virtual SkBitmap* GetIcon() const OVERRIDE;
309   virtual string16 GetMessageText() const OVERRIDE;
310   virtual int GetButtons() const OVERRIDE;
311   virtual string16 GetButtonLabel(InfoBarButton button) const OVERRIDE;
312   virtual bool Accept() OVERRIDE;
313 
314   // The Profile that we restore sessions from.
315   Profile* profile_;
316 
317   DISALLOW_COPY_AND_ASSIGN(SessionCrashedInfoBarDelegate);
318 };
319 
SessionCrashedInfoBarDelegate(TabContents * contents)320 SessionCrashedInfoBarDelegate::SessionCrashedInfoBarDelegate(
321     TabContents* contents)
322     : ConfirmInfoBarDelegate(contents),
323       profile_(contents->profile()) {
324 }
325 
~SessionCrashedInfoBarDelegate()326 SessionCrashedInfoBarDelegate::~SessionCrashedInfoBarDelegate() {
327 }
328 
InfoBarClosed()329 void SessionCrashedInfoBarDelegate::InfoBarClosed() {
330   delete this;
331 }
332 
GetIcon() const333 SkBitmap* SessionCrashedInfoBarDelegate::GetIcon() const {
334   return ResourceBundle::GetSharedInstance().GetBitmapNamed(
335       IDR_INFOBAR_RESTORE_SESSION);
336 }
337 
GetMessageText() const338 string16 SessionCrashedInfoBarDelegate::GetMessageText() const {
339   return l10n_util::GetStringUTF16(IDS_SESSION_CRASHED_VIEW_MESSAGE);
340 }
341 
GetButtons() const342 int SessionCrashedInfoBarDelegate::GetButtons() const {
343   return BUTTON_OK;
344 }
345 
GetButtonLabel(InfoBarButton button) const346 string16 SessionCrashedInfoBarDelegate::GetButtonLabel(
347     InfoBarButton button) const {
348   DCHECK_EQ(BUTTON_OK, button);
349   return l10n_util::GetStringUTF16(IDS_SESSION_CRASHED_VIEW_RESTORE_BUTTON);
350 }
351 
Accept()352 bool SessionCrashedInfoBarDelegate::Accept() {
353   SessionRestore::RestoreSession(profile_, NULL, true, false,
354                                  std::vector<GURL>());
355   return true;
356 }
357 
358 
359 // Utility functions ----------------------------------------------------------
360 
GetSessionStartupPref(const CommandLine & command_line,Profile * profile)361 SessionStartupPref GetSessionStartupPref(const CommandLine& command_line,
362                                          Profile* profile) {
363   SessionStartupPref pref = SessionStartupPref::GetStartupPref(profile);
364   if (command_line.HasSwitch(switches::kRestoreLastSession))
365     pref.type = SessionStartupPref::LAST;
366   if (command_line.HasSwitch(switches::kIncognito) &&
367       pref.type == SessionStartupPref::LAST &&
368       profile->GetPrefs()->GetBoolean(prefs::kIncognitoEnabled)) {
369     // We don't store session information when incognito. If the user has
370     // chosen to restore last session and launched incognito, fallback to
371     // default launch behavior.
372     pref.type = SessionStartupPref::DEFAULT;
373   }
374   return pref;
375 }
376 
377 enum LaunchMode {
378   LM_TO_BE_DECIDED = 0,       // Possibly direct launch or via a shortcut.
379   LM_AS_WEBAPP,               // Launched as a installed web application.
380   LM_WITH_URLS,               // Launched with urls in the cmd line.
381   LM_SHORTCUT_NONE,           // Not launched from a shortcut.
382   LM_SHORTCUT_NONAME,         // Launched from shortcut but no name available.
383   LM_SHORTCUT_UNKNOWN,        // Launched from user-defined shortcut.
384   LM_SHORTCUT_QUICKLAUNCH,    // Launched from the quick launch bar.
385   LM_SHORTCUT_DESKTOP,        // Launched from a desktop shortcut.
386   LM_SHORTCUT_STARTMENU,      // Launched from start menu.
387   LM_LINUX_MAC_BEOS           // Other OS buckets start here.
388 };
389 
390 #if defined(OS_WIN)
391 // Undocumented flag in the startup info structure tells us what shortcut was
392 // used to launch the browser. See http://www.catch22.net/tuts/undoc01 for
393 // more information. Confirmed to work on XP, Vista and Win7.
GetLaunchShortcutKind()394 LaunchMode GetLaunchShortcutKind() {
395   STARTUPINFOW si = { sizeof(si) };
396   GetStartupInfoW(&si);
397   if (si.dwFlags & 0x800) {
398     if (!si.lpTitle)
399       return LM_SHORTCUT_NONAME;
400     std::wstring shortcut(si.lpTitle);
401     // The windows quick launch path is not localized.
402     if (shortcut.find(L"\\Quick Launch\\") != std::wstring::npos)
403       return LM_SHORTCUT_QUICKLAUNCH;
404     scoped_ptr<base::Environment> env(base::Environment::Create());
405     std::string appdata_path;
406     env->GetVar("USERPROFILE", &appdata_path);
407     if (!appdata_path.empty() &&
408         shortcut.find(ASCIIToWide(appdata_path)) != std::wstring::npos)
409       return LM_SHORTCUT_DESKTOP;
410     return LM_SHORTCUT_UNKNOWN;
411   }
412   return LM_SHORTCUT_NONE;
413 }
414 #else
415 // TODO(cpu): Port to other platforms.
GetLaunchShortcutKind()416 LaunchMode GetLaunchShortcutKind() {
417   return LM_LINUX_MAC_BEOS;
418 }
419 #endif
420 
421 // Log in a histogram the frequency of launching by the different methods. See
422 // LaunchMode enum for the actual values of the buckets.
RecordLaunchModeHistogram(LaunchMode mode)423 void RecordLaunchModeHistogram(LaunchMode mode) {
424   int bucket = (mode == LM_TO_BE_DECIDED) ? GetLaunchShortcutKind() : mode;
425   UMA_HISTOGRAM_COUNTS_100("Launch.Modes", bucket);
426 }
427 
428 static bool in_startup = false;
429 
GetWelcomePageURL()430 GURL GetWelcomePageURL() {
431   std::string welcome_url = l10n_util::GetStringUTF8(IDS_WELCOME_PAGE_URL);
432   return GURL(welcome_url);
433 }
434 
UrlsToTabs(const std::vector<GURL> & urls,std::vector<BrowserInit::LaunchWithProfile::Tab> * tabs)435 void UrlsToTabs(const std::vector<GURL>& urls,
436                 std::vector<BrowserInit::LaunchWithProfile::Tab>* tabs) {
437   for (size_t i = 0; i < urls.size(); ++i) {
438     BrowserInit::LaunchWithProfile::Tab tab;
439     tab.is_pinned = false;
440     tab.url = urls[i];
441     tabs->push_back(tab);
442   }
443 }
444 
445 // Return true if the command line option --app-id is used.  Set
446 // |out_extension| to the app to open, and |out_launch_container|
447 // to the type of window into which the app should be open.
GetAppLaunchContainer(Profile * profile,const std::string & app_id,const Extension ** out_extension,extension_misc::LaunchContainer * out_launch_container)448 bool GetAppLaunchContainer(
449     Profile* profile,
450     const std::string& app_id,
451     const Extension** out_extension,
452     extension_misc::LaunchContainer* out_launch_container) {
453 
454   ExtensionService* extensions_service = profile->GetExtensionService();
455   const Extension* extension =
456       extensions_service->GetExtensionById(app_id, false);
457 
458   // The extension with id |app_id| may have been uninstalled.
459   if (!extension)
460     return false;
461 
462   // Look at preferences to find the right launch container.  If no
463   // preference is set, launch as a window.
464   extension_misc::LaunchContainer launch_container =
465       extensions_service->extension_prefs()->GetLaunchContainer(
466           extension, ExtensionPrefs::LAUNCH_WINDOW);
467 
468   *out_extension = extension;
469   *out_launch_container = launch_container;
470   return true;
471 }
472 
RecordCmdLineAppHistogram()473 void RecordCmdLineAppHistogram() {
474   UMA_HISTOGRAM_ENUMERATION(extension_misc::kAppLaunchHistogram,
475                             extension_misc::APP_LAUNCH_CMD_LINE_APP,
476                             extension_misc::APP_LAUNCH_BUCKET_BOUNDARY);
477 }
478 
RecordAppLaunches(Profile * profile,const std::vector<GURL> & cmd_line_urls,const std::vector<BrowserInit::LaunchWithProfile::Tab> & autolaunch_tabs)479 void RecordAppLaunches(
480     Profile* profile,
481     const std::vector<GURL>& cmd_line_urls,
482     const std::vector<BrowserInit::LaunchWithProfile::Tab>& autolaunch_tabs) {
483   ExtensionService* extension_service = profile->GetExtensionService();
484   DCHECK(extension_service);
485   for (size_t i = 0; i < cmd_line_urls.size(); ++i) {
486     if (extension_service->IsInstalledApp(cmd_line_urls.at(i))) {
487       UMA_HISTOGRAM_ENUMERATION(extension_misc::kAppLaunchHistogram,
488                                 extension_misc::APP_LAUNCH_CMD_LINE_URL,
489                                 extension_misc::APP_LAUNCH_BUCKET_BOUNDARY);
490     }
491   }
492   for (size_t i = 0; i < autolaunch_tabs.size(); ++i) {
493     if (extension_service->IsInstalledApp(autolaunch_tabs.at(i).url)) {
494       UMA_HISTOGRAM_ENUMERATION(extension_misc::kAppLaunchHistogram,
495                                 extension_misc::APP_LAUNCH_AUTOLAUNCH,
496                                 extension_misc::APP_LAUNCH_BUCKET_BOUNDARY);
497     }
498   }
499 }
500 
501 }  // namespace
502 
503 
504 // BrowserInit ----------------------------------------------------------------
505 
BrowserInit()506 BrowserInit::BrowserInit() {}
507 
~BrowserInit()508 BrowserInit::~BrowserInit() {}
509 
AddFirstRunTab(const GURL & url)510 void BrowserInit::AddFirstRunTab(const GURL& url) {
511   first_run_tabs_.push_back(url);
512 }
513 
514 // static
InProcessStartup()515 bool BrowserInit::InProcessStartup() {
516   return in_startup;
517 }
518 
LaunchBrowser(const CommandLine & command_line,Profile * profile,const FilePath & cur_dir,bool process_startup,int * return_code)519 bool BrowserInit::LaunchBrowser(const CommandLine& command_line,
520                                 Profile* profile,
521                                 const FilePath& cur_dir,
522                                 bool process_startup,
523                                 int* return_code) {
524   in_startup = process_startup;
525   DCHECK(profile);
526 #if defined(OS_CHROMEOS)
527   if (process_startup) {
528     // NetworkStateNotifier has to be initialized before Launching browser
529     // because the page load can happen in parallel to this UI thread
530     // and IO thread may access the NetworkStateNotifier.
531     chromeos::CrosLibrary::Get()->GetNetworkLibrary()
532         ->AddNetworkManagerObserver(
533             chromeos::NetworkStateNotifier::GetInstance());
534   }
535 #endif
536 
537   // Continue with the incognito profile from here on if --incognito
538   if (command_line.HasSwitch(switches::kIncognito) &&
539       profile->GetPrefs()->GetBoolean(prefs::kIncognitoEnabled)) {
540     profile = profile->GetOffTheRecordProfile();
541   }
542 
543   BrowserInit::LaunchWithProfile lwp(cur_dir, command_line, this);
544   std::vector<GURL> urls_to_launch = BrowserInit::GetURLsFromCommandLine(
545       command_line, cur_dir, profile);
546   bool launched = lwp.Launch(profile, urls_to_launch, process_startup);
547   in_startup = false;
548 
549   if (!launched) {
550     LOG(ERROR) << "launch error";
551     if (return_code)
552       *return_code = ResultCodes::INVALID_CMDLINE_URL;
553     return false;
554   }
555 
556 #if defined(OS_CHROMEOS)
557   // Initialize Chrome OS preferences like touch pad sensitivity. For the
558   // preferences to work in the guest mode, the initialization has to be
559   // done after |profile| is switched to the incognito profile (which
560   // is actually GuestSessionProfile in the guest mode). See the
561   // GetOffTheRecordProfile() call above.
562   profile->InitChromeOSPreferences();
563 
564   // Create the WmMessageListener so that it can listen for messages regardless
565   // of what window has focus.
566   chromeos::WmMessageListener::GetInstance();
567 
568   // Create the WmOverviewController so it can register with the listener.
569   chromeos::WmOverviewController::GetInstance();
570 
571   // Install the GView request interceptor that will redirect requests
572   // of compatible documents (PDF, etc) to the GView document viewer.
573   const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess();
574   if (parsed_command_line.HasSwitch(switches::kEnableGView)) {
575     chromeos::GViewRequestInterceptor::GetInstance();
576   }
577   if (process_startup) {
578     // This observer is a singleton. It is never deleted but the pointer is kept
579     // in a static so that it isn't reported as a leak.
580     static chromeos::LowBatteryObserver* low_battery_observer =
581         new chromeos::LowBatteryObserver(profile);
582     chromeos::CrosLibrary::Get()->GetPowerLibrary()->AddObserver(
583         low_battery_observer);
584 
585     static chromeos::UpdateObserver* update_observer =
586         new chromeos::UpdateObserver(profile);
587     chromeos::CrosLibrary::Get()->GetUpdateLibrary()->AddObserver(
588         update_observer);
589 
590     static chromeos::NetworkMessageObserver* network_message_observer =
591         new chromeos::NetworkMessageObserver(profile);
592     chromeos::CrosLibrary::Get()->GetNetworkLibrary()
593         ->AddNetworkManagerObserver(network_message_observer);
594     chromeos::CrosLibrary::Get()->GetNetworkLibrary()
595         ->AddCellularDataPlanObserver(network_message_observer);
596     chromeos::CrosLibrary::Get()->GetNetworkLibrary()
597         ->AddUserActionObserver(network_message_observer);
598 
599     static chromeos::SmsObserver* sms_observer =
600         new chromeos::SmsObserver(profile);
601     chromeos::CrosLibrary::Get()->GetNetworkLibrary()
602         ->AddNetworkManagerObserver(sms_observer);
603 
604     profile->SetupChromeOSEnterpriseExtensionObserver();
605   }
606 #endif
607   return true;
608 }
609 
610 
611 // BrowserInit::LaunchWithProfile::Tab ----------------------------------------
612 
Tab()613 BrowserInit::LaunchWithProfile::Tab::Tab() : is_app(false), is_pinned(true) {}
614 
~Tab()615 BrowserInit::LaunchWithProfile::Tab::~Tab() {}
616 
617 
618 // BrowserInit::LaunchWithProfile ---------------------------------------------
619 
LaunchWithProfile(const FilePath & cur_dir,const CommandLine & command_line)620 BrowserInit::LaunchWithProfile::LaunchWithProfile(
621     const FilePath& cur_dir,
622     const CommandLine& command_line)
623         : cur_dir_(cur_dir),
624           command_line_(command_line),
625           profile_(NULL),
626           browser_init_(NULL) {
627 }
628 
LaunchWithProfile(const FilePath & cur_dir,const CommandLine & command_line,BrowserInit * browser_init)629 BrowserInit::LaunchWithProfile::LaunchWithProfile(
630     const FilePath& cur_dir,
631     const CommandLine& command_line,
632     BrowserInit* browser_init)
633         : cur_dir_(cur_dir),
634           command_line_(command_line),
635           profile_(NULL),
636           browser_init_(browser_init) {
637 }
638 
~LaunchWithProfile()639 BrowserInit::LaunchWithProfile::~LaunchWithProfile() {
640 }
641 
Launch(Profile * profile,const std::vector<GURL> & urls_to_open,bool process_startup)642 bool BrowserInit::LaunchWithProfile::Launch(
643     Profile* profile,
644     const std::vector<GURL>& urls_to_open,
645     bool process_startup) {
646   DCHECK(profile);
647   profile_ = profile;
648 
649   if (command_line_.HasSwitch(switches::kDnsLogDetails))
650     chrome_browser_net::EnablePredictorDetailedLog(true);
651   if (command_line_.HasSwitch(switches::kDnsPrefetchDisable))
652     chrome_browser_net::EnablePredictor(false);
653 
654   if (command_line_.HasSwitch(switches::kDumpHistogramsOnExit))
655     base::StatisticsRecorder::set_dump_on_exit(true);
656 
657   if (command_line_.HasSwitch(switches::kRemoteShellPort)) {
658     std::string port_str =
659         command_line_.GetSwitchValueASCII(switches::kRemoteShellPort);
660     int64 port;
661     if (base::StringToInt64(port_str, &port) && port > 0 && port < 65535) {
662       g_browser_process->InitDevToolsLegacyProtocolHandler(
663           static_cast<int>(port));
664     } else {
665       DLOG(WARNING) << "Invalid remote shell port number " << port;
666     }
667   } else if (command_line_.HasSwitch(switches::kRemoteDebuggingPort)) {
668     std::string port_str =
669         command_line_.GetSwitchValueASCII(switches::kRemoteDebuggingPort);
670     int64 port;
671     if (base::StringToInt64(port_str, &port) && port > 0 && port < 65535) {
672       g_browser_process->InitDevToolsHttpProtocolHandler(
673           "127.0.0.1",
674           static_cast<int>(port),
675           "");
676     } else {
677       DLOG(WARNING) << "Invalid http debugger port number " << port;
678     }
679   }
680 
681   if (command_line_.HasSwitch(switches::kUserAgent)) {
682     webkit_glue::SetUserAgent(command_line_.GetSwitchValueASCII(
683         switches::kUserAgent));
684   }
685 
686   // Open the required browser windows and tabs. First, see if
687   // we're being run as an application window. If so, the user
688   // opened an app shortcut.  Don't restore tabs or open initial
689   // URLs in that case. The user should see the window as an app,
690   // not as chrome.
691   if (OpenApplicationWindow(profile)) {
692     RecordLaunchModeHistogram(LM_AS_WEBAPP);
693   } else {
694     RecordLaunchModeHistogram(urls_to_open.empty()?
695                               LM_TO_BE_DECIDED : LM_WITH_URLS);
696     ProcessLaunchURLs(process_startup, urls_to_open);
697 
698     // If this is an app launch, but we didn't open an app window, it may
699     // be an app tab.
700     OpenApplicationTab(profile);
701 
702     if (process_startup) {
703       if (browser_defaults::kOSSupportsOtherBrowsers &&
704           !command_line_.HasSwitch(switches::kNoDefaultBrowserCheck)) {
705         // Check whether we are the default browser.
706         CheckDefaultBrowser(profile);
707       }
708 #if defined(OS_MACOSX)
709       // Check whether the auto-update system needs to be promoted from user
710       // to system.
711       KeystoneInfoBar::PromotionInfoBar(profile);
712 #endif
713     }
714   }
715 
716 #if defined(OS_WIN)
717   // Print the selected page if the command line switch exists. Note that the
718   // current selected tab would be the page which will be printed.
719   if (command_line_.HasSwitch(switches::kPrint)) {
720     Browser* browser = BrowserList::GetLastActive();
721     browser->Print();
722   }
723 #endif
724 
725   // If we're recording or playing back, startup the EventRecorder now
726   // unless otherwise specified.
727   if (!command_line_.HasSwitch(switches::kNoEvents)) {
728     FilePath script_path;
729     PathService::Get(chrome::FILE_RECORDED_SCRIPT, &script_path);
730 
731     bool record_mode = command_line_.HasSwitch(switches::kRecordMode);
732     bool playback_mode = command_line_.HasSwitch(switches::kPlaybackMode);
733 
734     if (record_mode && chrome::kRecordModeEnabled)
735       base::EventRecorder::current()->StartRecording(script_path);
736     if (playback_mode)
737       base::EventRecorder::current()->StartPlayback(script_path);
738   }
739 
740 #if defined(OS_WIN)
741   if (process_startup)
742     ShellIntegration::MigrateChromiumShortcuts();
743 #endif  // defined(OS_WIN)
744 
745   return true;
746 }
747 
IsAppLaunch(std::string * app_url,std::string * app_id)748 bool BrowserInit::LaunchWithProfile::IsAppLaunch(std::string* app_url,
749                                                  std::string* app_id) {
750   if (command_line_.HasSwitch(switches::kApp)) {
751     if (app_url)
752       *app_url = command_line_.GetSwitchValueASCII(switches::kApp);
753     return true;
754   }
755   if (command_line_.HasSwitch(switches::kAppId)) {
756     if (app_id)
757       *app_id = command_line_.GetSwitchValueASCII(switches::kAppId);
758     return true;
759   }
760   return false;
761 }
762 
OpenApplicationTab(Profile * profile)763 bool BrowserInit::LaunchWithProfile::OpenApplicationTab(Profile* profile) {
764   std::string app_id;
765   // App shortcuts to URLs always open in an app window.  Because this
766   // function will open an app that should be in a tab, there is no need
767   // to look at the app URL.  OpenApplicationWindow() will open app url
768   // shortcuts.
769   if (!IsAppLaunch(NULL, &app_id) || app_id.empty())
770     return false;
771 
772   extension_misc::LaunchContainer launch_container;
773   const Extension* extension;
774   if (!GetAppLaunchContainer(profile, app_id, &extension, &launch_container))
775     return false;
776 
777   // If the user doesn't want to open a tab, fail.
778   if (launch_container != extension_misc::LAUNCH_TAB)
779     return false;
780 
781   RecordCmdLineAppHistogram();
782 
783   TabContents* app_tab = Browser::OpenApplicationTab(profile, extension, NULL);
784   return (app_tab != NULL);
785 }
786 
OpenApplicationWindow(Profile * profile)787 bool BrowserInit::LaunchWithProfile::OpenApplicationWindow(Profile* profile) {
788   std::string url_string, app_id;
789   if (!IsAppLaunch(&url_string, &app_id))
790     return false;
791 
792   // This can fail if the app_id is invalid.  It can also fail if the
793   // extension is external, and has not yet been installed.
794   // TODO(skerner): Do something reasonable here. Pop up a warning panel?
795   // Open an URL to the gallery page of the extension id?
796   if (!app_id.empty()) {
797     extension_misc::LaunchContainer launch_container;
798     const Extension* extension;
799     if (!GetAppLaunchContainer(profile, app_id, &extension, &launch_container))
800       return false;
801 
802     // TODO(skerner): Could pass in |extension| and |launch_container|,
803     // and avoid calling GetAppLaunchContainer() both here and in
804     // OpenApplicationTab().
805 
806     if (launch_container == extension_misc::LAUNCH_TAB)
807       return false;
808 
809     RecordCmdLineAppHistogram();
810     TabContents* tab_in_app_window = Browser::OpenApplication(
811         profile, extension, launch_container, NULL);
812     return (tab_in_app_window != NULL);
813   }
814 
815   if (url_string.empty())
816     return false;
817 
818 #if defined(OS_WIN)  // Fix up Windows shortcuts.
819   ReplaceSubstringsAfterOffset(&url_string, 0, "\\x", "%");
820 #endif
821   GURL url(url_string);
822 
823   // Restrict allowed URLs for --app switch.
824   if (!url.is_empty() && url.is_valid()) {
825     ChildProcessSecurityPolicy *policy =
826         ChildProcessSecurityPolicy::GetInstance();
827     if (policy->IsWebSafeScheme(url.scheme()) ||
828         url.SchemeIs(chrome::kFileScheme)) {
829 
830       if (profile->GetExtensionService()->IsInstalledApp(url)) {
831         RecordCmdLineAppHistogram();
832       } else {
833         UMA_HISTOGRAM_ENUMERATION(
834             extension_misc::kAppLaunchHistogram,
835             extension_misc::APP_LAUNCH_CMD_LINE_APP_LEGACY,
836             extension_misc::APP_LAUNCH_BUCKET_BOUNDARY);
837       }
838       TabContents* app_tab = Browser::OpenAppShortcutWindow(
839           profile,
840           url,
841           true);  // Update app info.
842       return (app_tab != NULL);
843     }
844   }
845   return false;
846 }
847 
ProcessLaunchURLs(bool process_startup,const std::vector<GURL> & urls_to_open)848 void BrowserInit::LaunchWithProfile::ProcessLaunchURLs(
849     bool process_startup,
850     const std::vector<GURL>& urls_to_open) {
851   // If we're starting up in "background mode" (no open browser window) then
852   // don't open any browser windows.
853   if (process_startup && command_line_.HasSwitch(switches::kNoStartupWindow))
854     return;
855 
856   if (process_startup && ProcessStartupURLs(urls_to_open)) {
857     // ProcessStartupURLs processed the urls, nothing else to do.
858     return;
859   }
860 
861   if (!process_startup &&
862       (profile_->GetSessionService() &&
863        profile_->GetSessionService()->RestoreIfNecessary(urls_to_open))) {
864     // We're already running and session restore wanted to run. This can happen
865     // at various points, such as if there is only an app window running and the
866     // user double clicked the chrome icon. Return so we don't open the urls.
867     return;
868   }
869 
870   // Session restore didn't occur, open the urls.
871 
872   Browser* browser = NULL;
873   std::vector<GURL> adjust_urls = urls_to_open;
874   if (adjust_urls.empty())
875     AddStartupURLs(&adjust_urls);
876   else if (!command_line_.HasSwitch(switches::kOpenInNewWindow))
877     browser = BrowserList::GetLastActiveWithProfile(profile_);
878 
879   browser = OpenURLsInBrowser(browser, process_startup, adjust_urls);
880   if (process_startup)
881     AddInfoBarsIfNecessary(browser);
882 }
883 
ProcessStartupURLs(const std::vector<GURL> & urls_to_open)884 bool BrowserInit::LaunchWithProfile::ProcessStartupURLs(
885     const std::vector<GURL>& urls_to_open) {
886   SessionStartupPref pref = GetSessionStartupPref(command_line_, profile_);
887   if (command_line_.HasSwitch(switches::kTestingChannelID) &&
888       !command_line_.HasSwitch(switches::kRestoreLastSession) &&
889       browser_defaults::kDefaultSessionStartupType !=
890       SessionStartupPref::DEFAULT) {
891     // When we have non DEFAULT session start type, then we won't open up a
892     // fresh session. But none of the tests are written with this in mind, so
893     // we explicitly ignore it during testing.
894     return false;
895   }
896 
897   if (pref.type == SessionStartupPref::LAST) {
898     if (!profile_->DidLastSessionExitCleanly() &&
899         !command_line_.HasSwitch(switches::kRestoreLastSession)) {
900       // The last session crashed. It's possible automatically loading the
901       // page will trigger another crash, locking the user out of chrome.
902       // To avoid this, don't restore on startup but instead show the crashed
903       // infobar.
904       return false;
905     }
906     Browser* browser =
907         SessionRestore::RestoreSessionSynchronously(profile_, urls_to_open);
908     AddInfoBarsIfNecessary(browser);
909     return true;
910   }
911 
912   std::vector<Tab> tabs = PinnedTabCodec::ReadPinnedTabs(profile_);
913 
914   RecordAppLaunches(profile_, urls_to_open, tabs);
915 
916   if (!urls_to_open.empty()) {
917     // If urls were specified on the command line, use them.
918     UrlsToTabs(urls_to_open, &tabs);
919   } else if (pref.type == SessionStartupPref::URLS && !pref.urls.empty()) {
920     // Only use the set of urls specified in preferences if nothing was
921     // specified on the command line. Filter out any urls that are to be
922     // restored by virtue of having been previously pinned.
923     AddUniqueURLs(pref.urls, &tabs);
924   } else if (pref.type == SessionStartupPref::DEFAULT && !tabs.empty()) {
925     // Make sure the home page is opened even if there are pinned tabs.
926     std::vector<GURL> urls;
927     AddStartupURLs(&urls);
928     UrlsToTabs(urls, &tabs);
929   }
930 
931   if (tabs.empty())
932     return false;
933 
934   Browser* browser = OpenTabsInBrowser(NULL, true, tabs);
935   AddInfoBarsIfNecessary(browser);
936   return true;
937 }
938 
AddUniqueURLs(const std::vector<GURL> & urls,std::vector<Tab> * tabs)939 void BrowserInit::LaunchWithProfile::AddUniqueURLs(
940     const std::vector<GURL>& urls,
941     std::vector<Tab>* tabs) {
942   size_t num_existing_tabs = tabs->size();
943   for (size_t i = 0; i < urls.size(); ++i) {
944     bool in_tabs = false;
945     for (size_t j = 0; j < num_existing_tabs; ++j) {
946       if (urls[i] == (*tabs)[j].url) {
947         in_tabs = true;
948         break;
949       }
950     }
951     if (!in_tabs) {
952       BrowserInit::LaunchWithProfile::Tab tab;
953       tab.is_pinned = false;
954       tab.url = urls[i];
955       tabs->push_back(tab);
956     }
957   }
958 }
959 
OpenURLsInBrowser(Browser * browser,bool process_startup,const std::vector<GURL> & urls)960 Browser* BrowserInit::LaunchWithProfile::OpenURLsInBrowser(
961     Browser* browser,
962     bool process_startup,
963     const std::vector<GURL>& urls) {
964   std::vector<Tab> tabs;
965   UrlsToTabs(urls, &tabs);
966   return OpenTabsInBrowser(browser, process_startup, tabs);
967 }
968 
OpenTabsInBrowser(Browser * browser,bool process_startup,const std::vector<Tab> & tabs)969 Browser* BrowserInit::LaunchWithProfile::OpenTabsInBrowser(
970         Browser* browser,
971         bool process_startup,
972         const std::vector<Tab>& tabs) {
973   DCHECK(!tabs.empty());
974   // If we don't yet have a profile, try to use the one we're given from
975   // |browser|. While we may not end up actually using |browser| (since it
976   // could be a popup window), we can at least use the profile.
977   if (!profile_ && browser)
978     profile_ = browser->profile();
979 
980   if (!browser || browser->type() != Browser::TYPE_NORMAL) {
981     browser = Browser::Create(profile_);
982   } else {
983 #if defined(TOOLKIT_GTK)
984     // Setting the time of the last action on the window here allows us to steal
985     // focus, which is what the user wants when opening a new tab in an existing
986     // browser window.
987     gtk_util::SetWMLastUserActionTime(browser->window()->GetNativeHandle());
988 #endif
989   }
990 
991 #if !defined(OS_MACOSX)
992   // In kiosk mode, we want to always be fullscreen, so switch to that now.
993   if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kKioskMode))
994     browser->ToggleFullscreenMode();
995 #endif
996 
997   bool first_tab = true;
998   for (size_t i = 0; i < tabs.size(); ++i) {
999     // We skip URLs that we'd have to launch an external protocol handler for.
1000     // This avoids us getting into an infinite loop asking ourselves to open
1001     // a URL, should the handler be (incorrectly) configured to be us. Anyone
1002     // asking us to open such a URL should really ask the handler directly.
1003     if (!process_startup && !net::URLRequest::IsHandledURL(tabs[i].url))
1004       continue;
1005 
1006     int add_types = first_tab ? TabStripModel::ADD_ACTIVE :
1007                                 TabStripModel::ADD_NONE;
1008     add_types |= TabStripModel::ADD_FORCE_INDEX;
1009     if (tabs[i].is_pinned)
1010       add_types |= TabStripModel::ADD_PINNED;
1011     int index = browser->GetIndexForInsertionDuringRestore(i);
1012 
1013     browser::NavigateParams params(browser, tabs[i].url,
1014                                    PageTransition::START_PAGE);
1015     params.disposition = first_tab ? NEW_FOREGROUND_TAB : NEW_BACKGROUND_TAB;
1016     params.tabstrip_index = index;
1017     params.tabstrip_add_types = add_types;
1018     params.extension_app_id = tabs[i].app_id;
1019     browser::Navigate(&params);
1020 
1021     first_tab = false;
1022   }
1023   browser->window()->Show();
1024   // TODO(jcampan): http://crbug.com/8123 we should not need to set the initial
1025   //                focus explicitly.
1026   browser->GetSelectedTabContents()->view()->SetInitialFocus();
1027 
1028   return browser;
1029 }
1030 
AddInfoBarsIfNecessary(Browser * browser)1031 void BrowserInit::LaunchWithProfile::AddInfoBarsIfNecessary(Browser* browser) {
1032   if (!browser || !profile_ || browser->tab_count() == 0)
1033     return;
1034 
1035   TabContents* tab_contents = browser->GetSelectedTabContents();
1036   AddCrashedInfoBarIfNecessary(tab_contents);
1037   AddBadFlagsInfoBarIfNecessary(tab_contents);
1038   AddDNSCertProvenanceCheckingWarningInfoBarIfNecessary(tab_contents);
1039   AddObsoleteSystemInfoBarIfNecessary(tab_contents);
1040 }
1041 
AddCrashedInfoBarIfNecessary(TabContents * tab)1042 void BrowserInit::LaunchWithProfile::AddCrashedInfoBarIfNecessary(
1043     TabContents* tab) {
1044   // Assume that if the user is launching incognito they were previously
1045   // running incognito so that we have nothing to restore from.
1046   if (!profile_->DidLastSessionExitCleanly() &&
1047       !profile_->IsOffTheRecord()) {
1048     // The last session didn't exit cleanly. Show an infobar to the user
1049     // so that they can restore if they want. The delegate deletes itself when
1050     // it is closed.
1051     tab->AddInfoBar(new SessionCrashedInfoBarDelegate(tab));
1052   }
1053 }
1054 
AddBadFlagsInfoBarIfNecessary(TabContents * tab)1055 void BrowserInit::LaunchWithProfile::AddBadFlagsInfoBarIfNecessary(
1056     TabContents* tab) {
1057   // Unsupported flags for which to display a warning that "stability and
1058   // security will suffer".
1059   static const char* kBadFlags[] = {
1060     // These imply disabling the sandbox.
1061     switches::kSingleProcess,
1062     switches::kNoSandbox,
1063     switches::kInProcessWebGL,
1064     // These are scary features for developers that shouldn't be turned on
1065     // persistently.
1066     switches::kEnableNaCl,
1067     NULL
1068   };
1069 
1070   const char* bad_flag = NULL;
1071   for (const char** flag = kBadFlags; *flag; ++flag) {
1072     if (command_line_.HasSwitch(*flag)) {
1073       bad_flag = *flag;
1074       break;
1075     }
1076   }
1077 
1078   if (bad_flag) {
1079     tab->AddInfoBar(new SimpleAlertInfoBarDelegate(tab, NULL,
1080         l10n_util::GetStringFUTF16(IDS_BAD_FLAGS_WARNING_MESSAGE,
1081                                    UTF8ToUTF16(std::string("--") + bad_flag)),
1082         false));
1083   }
1084 }
1085 
1086 class LearnMoreInfoBar : public LinkInfoBarDelegate {
1087  public:
1088   explicit LearnMoreInfoBar(TabContents* tab_contents,
1089                             const string16& message,
1090                             const GURL& url);
1091   virtual ~LearnMoreInfoBar();
1092 
1093   virtual string16 GetMessageTextWithOffset(size_t* link_offset) const OVERRIDE;
1094   virtual string16 GetLinkText() const OVERRIDE;
1095   virtual bool LinkClicked(WindowOpenDisposition disposition) OVERRIDE;
1096 
1097  private:
1098   TabContents* const tab_contents_;
1099   string16 message_;
1100   GURL learn_more_url_;
1101 
1102   DISALLOW_COPY_AND_ASSIGN(LearnMoreInfoBar);
1103 };
1104 
LearnMoreInfoBar(TabContents * tab_contents,const string16 & message,const GURL & url)1105 LearnMoreInfoBar::LearnMoreInfoBar(TabContents* tab_contents,
1106                                    const string16& message,
1107                                    const GURL& url)
1108     : LinkInfoBarDelegate(tab_contents),
1109       tab_contents_(tab_contents),
1110       message_(message),
1111       learn_more_url_(url) {
1112 }
1113 
~LearnMoreInfoBar()1114 LearnMoreInfoBar::~LearnMoreInfoBar() {
1115 }
1116 
GetMessageTextWithOffset(size_t * link_offset) const1117 string16 LearnMoreInfoBar::GetMessageTextWithOffset(size_t* link_offset) const {
1118   string16 text = message_;
1119   text.push_back(' ');  // Add a space before the following link.
1120   *link_offset = text.size();
1121   return text;
1122 }
1123 
GetLinkText() const1124 string16 LearnMoreInfoBar::GetLinkText() const {
1125   return l10n_util::GetStringUTF16(IDS_LEARN_MORE);
1126 }
1127 
LinkClicked(WindowOpenDisposition disposition)1128 bool LearnMoreInfoBar::LinkClicked(WindowOpenDisposition disposition) {
1129   tab_contents_->OpenURL(learn_more_url_, GURL(), disposition,
1130                          PageTransition::LINK);
1131   return false;
1132 }
1133 
1134 // This is the page which provides information on DNS certificate provenance
1135 // checking.
1136 void BrowserInit::LaunchWithProfile::
AddDNSCertProvenanceCheckingWarningInfoBarIfNecessary(TabContents * tab)1137     AddDNSCertProvenanceCheckingWarningInfoBarIfNecessary(TabContents* tab) {
1138   if (!command_line_.HasSwitch(switches::kEnableDNSCertProvenanceChecking))
1139     return;
1140 
1141   const char* kLearnMoreURL =
1142       "http://dev.chromium.org/dnscertprovenancechecking";
1143   string16 message = l10n_util::GetStringUTF16(
1144       IDS_DNS_CERT_PROVENANCE_CHECKING_WARNING_MESSAGE);
1145   tab->AddInfoBar(new LearnMoreInfoBar(tab,
1146                                        message,
1147                                        GURL(kLearnMoreURL)));
1148 }
1149 
AddObsoleteSystemInfoBarIfNecessary(TabContents * tab)1150 void BrowserInit::LaunchWithProfile::AddObsoleteSystemInfoBarIfNecessary(
1151     TabContents* tab) {
1152 #if defined(TOOLKIT_USES_GTK)
1153   // We've deprecated support for Ubuntu Hardy.  Rather than attempting to
1154   // determine whether you're using that, we instead key off the GTK version;
1155   // this will also deprecate other distributions (including variants of Ubuntu)
1156   // that are of a similar age.
1157   // Version key:
1158   //   Ubuntu Hardy: GTK 2.12
1159   //   RHEL 6:       GTK 2.18
1160   //   Ubuntu Lucid: GTK 2.20
1161   if (gtk_check_version(2, 18, 0)) {
1162     string16 message =
1163         l10n_util::GetStringFUTF16(IDS_SYSTEM_OBSOLETE_MESSAGE,
1164                                    l10n_util::GetStringUTF16(IDS_PRODUCT_NAME));
1165     // Link to an article in the help center on minimum system requirements.
1166     const char* kLearnMoreURL =
1167         "http://www.google.com/support/chrome/bin/answer.py?answer=95411";
1168     tab->AddInfoBar(new LearnMoreInfoBar(tab,
1169                                          message,
1170                                          GURL(kLearnMoreURL)));
1171   }
1172 #endif
1173 }
1174 
AddStartupURLs(std::vector<GURL> * startup_urls) const1175 void BrowserInit::LaunchWithProfile::AddStartupURLs(
1176     std::vector<GURL>* startup_urls) const {
1177   // If we have urls specified beforehand (i.e. from command line) use them
1178   // and nothing else.
1179   if (!startup_urls->empty())
1180     return;
1181   // If we have urls specified by the first run master preferences use them
1182   // and nothing else.
1183   if (browser_init_) {
1184     if (!browser_init_->first_run_tabs_.empty()) {
1185       std::vector<GURL>::iterator it = browser_init_->first_run_tabs_.begin();
1186       while (it != browser_init_->first_run_tabs_.end()) {
1187         // Replace magic names for the actual urls.
1188         if (it->host() == "new_tab_page") {
1189           startup_urls->push_back(GURL(chrome::kChromeUINewTabURL));
1190         } else if (it->host() == "welcome_page") {
1191           startup_urls->push_back(GetWelcomePageURL());
1192         } else {
1193           startup_urls->push_back(*it);
1194         }
1195         ++it;
1196       }
1197       browser_init_->first_run_tabs_.clear();
1198       return;
1199     }
1200   }
1201 
1202   // Otherwise open at least the new tab page (and the welcome page, if this
1203   // is the first time the browser is being started), or the set of URLs
1204   // specified on the command line.
1205   startup_urls->push_back(GURL());  // New tab page.
1206   PrefService* prefs = g_browser_process->local_state();
1207   if (prefs->FindPreference(prefs::kShouldShowWelcomePage) &&
1208       prefs->GetBoolean(prefs::kShouldShowWelcomePage)) {
1209     // Reset the preference so we don't show the welcome page next time.
1210     prefs->ClearPref(prefs::kShouldShowWelcomePage);
1211     startup_urls->push_back(GetWelcomePageURL());
1212   }
1213 }
1214 
CheckDefaultBrowser(Profile * profile)1215 void BrowserInit::LaunchWithProfile::CheckDefaultBrowser(Profile* profile) {
1216   // We do not check if we are the default browser if:
1217   // - the user said "don't ask me again" on the infobar earlier.
1218   // - this is the first launch after the first run flow.
1219   // - There is a policy in control of this setting.
1220   if (!profile->GetPrefs()->GetBoolean(prefs::kCheckDefaultBrowser) ||
1221       FirstRun::IsChromeFirstRun()) {
1222     return;
1223   }
1224   if (g_browser_process->local_state()->IsManagedPreference(
1225       prefs::kDefaultBrowserSettingEnabled)) {
1226     if (g_browser_process->local_state()->GetBoolean(
1227         prefs::kDefaultBrowserSettingEnabled)) {
1228       BrowserThread::PostTask(
1229           BrowserThread::FILE, FROM_HERE, NewRunnableFunction(
1230               &ShellIntegration::SetAsDefaultBrowser));
1231     } else {
1232       // TODO(pastarmovj): We can't really do anything meaningful here yet but
1233       // just prevent showing the infobar.
1234     }
1235     return;
1236   }
1237   BrowserThread::PostTask(
1238       BrowserThread::FILE, FROM_HERE, new CheckDefaultBrowserTask());
1239 }
1240 
GetURLsFromCommandLine(const CommandLine & command_line,const FilePath & cur_dir,Profile * profile)1241 std::vector<GURL> BrowserInit::GetURLsFromCommandLine(
1242     const CommandLine& command_line,
1243     const FilePath& cur_dir,
1244     Profile* profile) {
1245   std::vector<GURL> urls;
1246   const std::vector<CommandLine::StringType>& params = command_line.args();
1247 
1248   for (size_t i = 0; i < params.size(); ++i) {
1249     FilePath param = FilePath(params[i]);
1250     // Handle Vista way of searching - "? <search-term>"
1251     if (param.value().size() > 2 &&
1252         param.value()[0] == '?' && param.value()[1] == ' ') {
1253       const TemplateURL* default_provider =
1254           profile->GetTemplateURLModel()->GetDefaultSearchProvider();
1255       if (default_provider && default_provider->url()) {
1256         const TemplateURLRef* search_url = default_provider->url();
1257         DCHECK(search_url->SupportsReplacement());
1258         string16 search_term = param.LossyDisplayName().substr(2);
1259         urls.push_back(GURL(search_url->ReplaceSearchTerms(
1260                                 *default_provider, search_term,
1261                                 TemplateURLRef::NO_SUGGESTIONS_AVAILABLE,
1262                                 string16())));
1263         continue;
1264       }
1265     }
1266 
1267     // Otherwise, fall through to treating it as a URL.
1268 
1269     // This will create a file URL or a regular URL.
1270     // This call can (in rare circumstances) block the UI thread.
1271     // Allow it until this bug is fixed.
1272     //  http://code.google.com/p/chromium/issues/detail?id=60641
1273     GURL url;
1274     {
1275       base::ThreadRestrictions::ScopedAllowIO allow_io;
1276       url = URLFixerUpper::FixupRelativeFile(cur_dir, param);
1277     }
1278     // Exclude dangerous schemes.
1279     if (url.is_valid()) {
1280       ChildProcessSecurityPolicy *policy =
1281           ChildProcessSecurityPolicy::GetInstance();
1282       if (policy->IsWebSafeScheme(url.scheme()) ||
1283           url.SchemeIs(chrome::kFileScheme) ||
1284 #if defined(OS_CHROMEOS)
1285           // In ChromeOS, allow a settings page to be specified on the
1286           // command line. See ExistingUserController::OnLoginSuccess.
1287           (url.spec().find(chrome::kChromeUISettingsURL) == 0) ||
1288 #endif
1289           (url.spec().compare(chrome::kAboutBlankURL) == 0)) {
1290         urls.push_back(url);
1291       }
1292     }
1293   }
1294   return urls;
1295 }
1296 
ProcessCmdLineImpl(const CommandLine & command_line,const FilePath & cur_dir,bool process_startup,Profile * profile,int * return_code,BrowserInit * browser_init)1297 bool BrowserInit::ProcessCmdLineImpl(const CommandLine& command_line,
1298                                      const FilePath& cur_dir,
1299                                      bool process_startup,
1300                                      Profile* profile,
1301                                      int* return_code,
1302                                      BrowserInit* browser_init) {
1303   DCHECK(profile);
1304   if (process_startup) {
1305     if (command_line.HasSwitch(switches::kDisablePromptOnRepost))
1306       NavigationController::DisablePromptOnRepost();
1307 
1308     // Look for the testing channel ID ONLY during process startup
1309     if (command_line.HasSwitch(switches::kTestingChannelID)) {
1310       std::string testing_channel_id = command_line.GetSwitchValueASCII(
1311           switches::kTestingChannelID);
1312       // TODO(sanjeevr) Check if we need to make this a singleton for
1313       // compatibility with the old testing code
1314       // If there are any extra parameters, we expect each one to generate a
1315       // new tab; if there are none then we get one homepage tab.
1316       int expected_tab_count = 1;
1317       if (command_line.HasSwitch(switches::kNoStartupWindow)) {
1318         expected_tab_count = 0;
1319 #if defined(OS_CHROMEOS)
1320       // kLoginManager will cause Chrome to start up with the ChromeOS login
1321       // screen instead of a browser window, so it won't load any tabs.
1322       } else if (command_line.HasSwitch(switches::kLoginManager)) {
1323         expected_tab_count = 0;
1324 #endif
1325       } else if (command_line.HasSwitch(switches::kRestoreLastSession)) {
1326         std::string restore_session_value(
1327             command_line.GetSwitchValueASCII(switches::kRestoreLastSession));
1328         base::StringToInt(restore_session_value, &expected_tab_count);
1329       } else {
1330         std::vector<GURL> urls_to_open = GetURLsFromCommandLine(
1331             command_line, cur_dir, profile);
1332         expected_tab_count =
1333             std::max(1, static_cast<int>(urls_to_open.size()));
1334       }
1335       if (!CreateAutomationProvider<TestingAutomationProvider>(
1336           testing_channel_id,
1337           profile,
1338           static_cast<size_t>(expected_tab_count)))
1339         return false;
1340     }
1341   }
1342 
1343   bool silent_launch = false;
1344 
1345   if (command_line.HasSwitch(switches::kAutomationClientChannelID)) {
1346     std::string automation_channel_id = command_line.GetSwitchValueASCII(
1347         switches::kAutomationClientChannelID);
1348     // If there are any extra parameters, we expect each one to generate a
1349     // new tab; if there are none then we have no tabs
1350     std::vector<GURL> urls_to_open = GetURLsFromCommandLine(
1351         command_line, cur_dir, profile);
1352     size_t expected_tabs =
1353         std::max(static_cast<int>(urls_to_open.size()), 0);
1354     if (expected_tabs == 0)
1355       silent_launch = true;
1356 
1357     if (command_line.HasSwitch(switches::kChromeFrame)) {
1358       if (!CreateAutomationProvider<ChromeFrameAutomationProvider>(
1359           automation_channel_id, profile, expected_tabs))
1360         return false;
1361     } else {
1362       if (!CreateAutomationProvider<AutomationProvider>(
1363           automation_channel_id, profile, expected_tabs))
1364         return false;
1365     }
1366   }
1367 
1368   // If we have been invoked to display a desktop notification on behalf of
1369   // the service process, we do not want to open any browser windows.
1370   if (command_line.HasSwitch(switches::kNotifyCloudPrintTokenExpired)) {
1371     silent_launch = true;
1372     profile->GetCloudPrintProxyService()->ShowTokenExpiredNotification();
1373   }
1374 
1375   // If we are just displaying a print dialog we shouldn't open browser
1376   // windows.
1377   if (print_dialog_cloud::CreatePrintDialogFromCommandLine(command_line)) {
1378     silent_launch = true;
1379   }
1380 
1381   if (command_line.HasSwitch(switches::kExplicitlyAllowedPorts)) {
1382     std::string allowed_ports =
1383         command_line.GetSwitchValueASCII(switches::kExplicitlyAllowedPorts);
1384     net::SetExplicitlyAllowedPorts(allowed_ports);
1385   }
1386 
1387 #if defined(OS_CHROMEOS)
1388   // The browser will be launched after the user logs in.
1389   if (command_line.HasSwitch(switches::kLoginManager) ||
1390       command_line.HasSwitch(switches::kLoginPassword)) {
1391     silent_launch = true;
1392   }
1393 #endif
1394 
1395 #if defined(HAVE_XINPUT2) && defined(TOUCH_UI)
1396   // Get a list of pointer-devices that should be treated as touch-devices.
1397   // TODO(sad): Instead of/in addition to getting the list from the
1398   // command-line, query X for a list of touch devices.
1399   std::string touch_devices =
1400     command_line.GetSwitchValueASCII(switches::kTouchDevices);
1401 
1402   if (!touch_devices.empty()) {
1403     std::vector<std::string> devs;
1404     std::vector<unsigned int> device_ids;
1405     unsigned int devid;
1406     base::SplitString(touch_devices, ',', &devs);
1407     for (std::vector<std::string>::iterator iter = devs.begin();
1408         iter != devs.end(); ++iter) {
1409       if (base::StringToInt(*iter, reinterpret_cast<int*>(&devid))) {
1410         device_ids.push_back(devid);
1411       } else {
1412         DLOG(WARNING) << "Invalid touch-device id: " << *iter;
1413       }
1414     }
1415     views::SetTouchDeviceList(device_ids);
1416   }
1417 #endif
1418 
1419   // If we don't want to launch a new browser window or tab (in the case
1420   // of an automation request), we are done here.
1421   if (!silent_launch) {
1422     return browser_init->LaunchBrowser(
1423         command_line, profile, cur_dir, process_startup, return_code);
1424   }
1425   return true;
1426 }
1427 
1428 template <class AutomationProviderClass>
CreateAutomationProvider(const std::string & channel_id,Profile * profile,size_t expected_tabs)1429 bool BrowserInit::CreateAutomationProvider(const std::string& channel_id,
1430                                            Profile* profile,
1431                                            size_t expected_tabs) {
1432   scoped_refptr<AutomationProviderClass> automation =
1433       new AutomationProviderClass(profile);
1434 
1435   if (!automation->InitializeChannel(channel_id))
1436     return false;
1437   automation->SetExpectedTabCount(expected_tabs);
1438 
1439   AutomationProviderList* list =
1440       g_browser_process->InitAutomationProviderList();
1441   DCHECK(list);
1442   list->AddProvider(automation);
1443 
1444   return true;
1445 }
1446