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(¶ms);
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