Home | History | Annotate | Download | only in ui
      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 
    120 SetAsDefaultBrowserTask::SetAsDefaultBrowserTask() {
    121 }
    122 
    123 SetAsDefaultBrowserTask::~SetAsDefaultBrowserTask() {
    124 }
    125 
    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 
    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 
    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 
    183 DefaultBrowserInfoBarDelegate::~DefaultBrowserInfoBarDelegate() {
    184 }
    185 
    186 bool DefaultBrowserInfoBarDelegate::ShouldExpire(
    187     const NavigationController::LoadCommittedDetails& details) const {
    188   return should_expire_;
    189 }
    190 
    191 void DefaultBrowserInfoBarDelegate::InfoBarClosed() {
    192   if (!action_taken_)
    193     UMA_HISTOGRAM_COUNTS("DefaultBrowserWarning.Ignored", 1);
    194   delete this;
    195 }
    196 
    197 SkBitmap* DefaultBrowserInfoBarDelegate::GetIcon() const {
    198   return ResourceBundle::GetSharedInstance().GetBitmapNamed(
    199      IDR_PRODUCT_ICON_32);
    200 }
    201 
    202 string16 DefaultBrowserInfoBarDelegate::GetMessageText() const {
    203   return l10n_util::GetStringUTF16(IDS_DEFAULT_BROWSER_INFOBAR_SHORT_TEXT);
    204 }
    205 
    206 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 
    213 bool DefaultBrowserInfoBarDelegate::NeedElevation(InfoBarButton button) const {
    214   return button == BUTTON_OK;
    215 }
    216 
    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 
    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 
    247 NotifyNotDefaultBrowserTask::NotifyNotDefaultBrowserTask() {
    248 }
    249 
    250 NotifyNotDefaultBrowserTask::~NotifyNotDefaultBrowserTask() {
    251 }
    252 
    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 
    280 CheckDefaultBrowserTask::CheckDefaultBrowserTask() {
    281 }
    282 
    283 CheckDefaultBrowserTask::~CheckDefaultBrowserTask() {
    284 }
    285 
    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 
    320 SessionCrashedInfoBarDelegate::SessionCrashedInfoBarDelegate(
    321     TabContents* contents)
    322     : ConfirmInfoBarDelegate(contents),
    323       profile_(contents->profile()) {
    324 }
    325 
    326 SessionCrashedInfoBarDelegate::~SessionCrashedInfoBarDelegate() {
    327 }
    328 
    329 void SessionCrashedInfoBarDelegate::InfoBarClosed() {
    330   delete this;
    331 }
    332 
    333 SkBitmap* SessionCrashedInfoBarDelegate::GetIcon() const {
    334   return ResourceBundle::GetSharedInstance().GetBitmapNamed(
    335       IDR_INFOBAR_RESTORE_SESSION);
    336 }
    337 
    338 string16 SessionCrashedInfoBarDelegate::GetMessageText() const {
    339   return l10n_util::GetStringUTF16(IDS_SESSION_CRASHED_VIEW_MESSAGE);
    340 }
    341 
    342 int SessionCrashedInfoBarDelegate::GetButtons() const {
    343   return BUTTON_OK;
    344 }
    345 
    346 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 
    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 
    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.
    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.
    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.
    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 
    430 GURL GetWelcomePageURL() {
    431   std::string welcome_url = l10n_util::GetStringUTF8(IDS_WELCOME_PAGE_URL);
    432   return GURL(welcome_url);
    433 }
    434 
    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.
    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 
    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 
    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 
    506 BrowserInit::BrowserInit() {}
    507 
    508 BrowserInit::~BrowserInit() {}
    509 
    510 void BrowserInit::AddFirstRunTab(const GURL& url) {
    511   first_run_tabs_.push_back(url);
    512 }
    513 
    514 // static
    515 bool BrowserInit::InProcessStartup() {
    516   return in_startup;
    517 }
    518 
    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 
    613 BrowserInit::LaunchWithProfile::Tab::Tab() : is_app(false), is_pinned(true) {}
    614 
    615 BrowserInit::LaunchWithProfile::Tab::~Tab() {}
    616 
    617 
    618 // BrowserInit::LaunchWithProfile ---------------------------------------------
    619 
    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 
    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 
    639 BrowserInit::LaunchWithProfile::~LaunchWithProfile() {
    640 }
    641 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
   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 
   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 
   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 
   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 
   1114 LearnMoreInfoBar::~LearnMoreInfoBar() {
   1115 }
   1116 
   1117 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 
   1124 string16 LearnMoreInfoBar::GetLinkText() const {
   1125   return l10n_util::GetStringUTF16(IDS_LEARN_MORE);
   1126 }
   1127 
   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::
   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 
   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 
   1175 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 
   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 
   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 
   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>
   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