browser.cc 99.3 KB
Newer Older
1
// Copyright 2012 The Chromium Authors. All rights reserved.
2
3
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
initial.commit's avatar
initial.commit committed
4

5
#include "chrome/browser/ui/browser.h"
6

7
#include <stddef.h>
8

9
10
#include <algorithm>
#include <string>
11
#include <utility>
12

13
#include "base/base_paths.h"
14
#include "base/bind.h"
15
#include "base/command_line.h"
16
#include "base/location.h"
17
#include "base/logging.h"
18
#include "base/macros.h"
19
#include "base/metrics/histogram.h"
20
#include "base/process/process_info.h"
21
#include "base/profiler/scoped_tracker.h"
22
#include "base/single_thread_task_runner.h"
23
#include "base/strings/string_number_conversions.h"
24
25
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
26
#include "base/strings/utf_string_conversions.h"
27
28
#include "base/threading/thread.h"
#include "base/threading/thread_restrictions.h"
29
#include "base/threading/thread_task_runner_handle.h"
30
#include "base/time/time.h"
31
#include "build/build_config.h"
32
#include "chrome/app/chrome_command_ids.h"
33
#include "chrome/browser/app_mode/app_mode_utils.h"
34
#include "chrome/browser/autofill/personal_data_manager_factory.h"
35
#include "chrome/browser/background/background_contents.h"
36
#include "chrome/browser/background/background_contents_service.h"
37
#include "chrome/browser/background/background_contents_service_factory.h"
38
#include "chrome/browser/banners/app_banner_manager_desktop.h"
39
#include "chrome/browser/banners/app_banner_manager_emulation.h"
40
#include "chrome/browser/browser_process.h"
41
#include "chrome/browser/browser_shutdown.h"
42
#include "chrome/browser/character_encoding.h"
43
#include "chrome/browser/chrome_notification_types.h"
44
#include "chrome/browser/content_settings/tab_specific_content_settings.h"
45
#include "chrome/browser/custom_handlers/protocol_handler_registry.h"
46
#include "chrome/browser/custom_handlers/protocol_handler_registry_factory.h"
47
#include "chrome/browser/custom_handlers/register_protocol_handler_permission_request.h"
48
#include "chrome/browser/defaults.h"
49
50
#include "chrome/browser/devtools/devtools_toggle_action.h"
#include "chrome/browser/devtools/devtools_window.h"
51
52
#include "chrome/browser/download/download_service.h"
#include "chrome/browser/download/download_service_factory.h"
53
54
#include "chrome/browser/extensions/api/tabs/tabs_event_router.h"
#include "chrome/browser/extensions/api/tabs/tabs_windows_api.h"
55
#include "chrome/browser/extensions/browser_extension_window_controller.h"
56
#include "chrome/browser/extensions/extension_service.h"
57
#include "chrome/browser/extensions/extension_ui_util.h"
58
#include "chrome/browser/extensions/extension_util.h"
59
#include "chrome/browser/extensions/tab_helper.h"
60
#include "chrome/browser/file_select_helper.h"
61
#include "chrome/browser/first_run/first_run.h"
62
#include "chrome/browser/history/top_sites_factory.h"
63
#include "chrome/browser/infobars/infobar_service.h"
64
#include "chrome/browser/lifetime/application_lifetime.h"
65
#include "chrome/browser/lifetime/keep_alive_registry.h"
66
67
#include "chrome/browser/lifetime/keep_alive_types.h"
#include "chrome/browser/lifetime/scoped_keep_alive.h"
68
#include "chrome/browser/memory/tab_manager_web_contents_data.h"
69
#include "chrome/browser/notifications/notification_ui_manager.h"
70
#include "chrome/browser/pepper_broker_infobar_delegate.h"
71
#include "chrome/browser/prefs/incognito_mode_prefs.h"
ben@chromium.org's avatar
Move:    
ben@chromium.org committed
72
#include "chrome/browser/profiles/profile.h"
73
#include "chrome/browser/profiles/profile_destroyer.h"
74
#include "chrome/browser/profiles/profile_metrics.h"
75
#include "chrome/browser/profiles/profiles_state.h"
76
#include "chrome/browser/repost_form_warning_controller.h"
77
#include "chrome/browser/search/search.h"
78
#include "chrome/browser/sessions/session_restore.h"
79
#include "chrome/browser/sessions/session_service.h"
80
#include "chrome/browser/sessions/session_service_factory.h"
81
#include "chrome/browser/sessions/session_tab_helper.h"
82
#include "chrome/browser/sessions/tab_restore_service_factory.h"
83
#include "chrome/browser/ssl/chrome_security_state_model_client.h"
84
#include "chrome/browser/sync/profile_sync_service_factory.h"
85
#include "chrome/browser/sync/sync_ui_util.h"
86
#include "chrome/browser/tab_contents/retargeting_details.h"
87
#include "chrome/browser/tab_contents/tab_util.h"
88
#include "chrome/browser/task_management/web_contents_tags.h"
89
90
#include "chrome/browser/themes/theme_service.h"
#include "chrome/browser/themes/theme_service_factory.h"
91
#include "chrome/browser/translate/chrome_translate_client.h"
92
#include "chrome/browser/ui/autofill/chrome_autofill_client.h"
93
#include "chrome/browser/ui/blocked_content/popup_blocker_tab_helper.h"
juncai's avatar
juncai committed
94
#include "chrome/browser/ui/bluetooth/bluetooth_chooser_controller.h"
95
#include "chrome/browser/ui/bluetooth/bluetooth_chooser_desktop.h"
96
#include "chrome/browser/ui/bookmarks/bookmark_tab_helper.h"
97
#include "chrome/browser/ui/bookmarks/bookmark_utils.h"
98
#include "chrome/browser/ui/browser_command_controller.h"
99
#include "chrome/browser/ui/browser_commands.h"
100
#include "chrome/browser/ui/browser_content_setting_bubble_model_delegate.h"
101
#include "chrome/browser/ui/browser_dialogs.h"
102
#include "chrome/browser/ui/browser_finder.h"
103
#include "chrome/browser/ui/browser_instant_controller.h"
104
#include "chrome/browser/ui/browser_list.h"
105
#include "chrome/browser/ui/browser_live_tab_context.h"
106
#include "chrome/browser/ui/browser_navigator.h"
107
#include "chrome/browser/ui/browser_navigator_params.h"
108
#include "chrome/browser/ui/browser_tab_strip_model_delegate.h"
109
#include "chrome/browser/ui/browser_tabstrip.h"
110
#include "chrome/browser/ui/browser_toolbar_model_delegate.h"
111
#include "chrome/browser/ui/browser_ui_prefs.h"
112
#include "chrome/browser/ui/browser_window.h"
113
#include "chrome/browser/ui/chrome_bubble_manager.h"
114
#include "chrome/browser/ui/chrome_pages.h"
115
#include "chrome/browser/ui/chrome_select_file_policy.h"
116
#include "chrome/browser/ui/exclusive_access/fullscreen_controller.h"
sriramsr's avatar
sriramsr committed
117
#include "chrome/browser/ui/exclusive_access/mouse_lock_controller.h"
118
#include "chrome/browser/ui/extensions/hosted_app_browser_controller.h"
119
#include "chrome/browser/ui/fast_unload_controller.h"
120
121
#include "chrome/browser/ui/find_bar/find_bar.h"
#include "chrome/browser/ui/find_bar/find_bar_controller.h"
122
#include "chrome/browser/ui/find_bar/find_tab_helper.h"
123
124
125
#include "chrome/browser/ui/global_error/global_error.h"
#include "chrome/browser/ui/global_error/global_error_service.h"
#include "chrome/browser/ui/global_error/global_error_service_factory.h"
126
#include "chrome/browser/ui/location_bar/location_bar.h"
127
#include "chrome/browser/ui/media_utils.h"
128
129
#include "chrome/browser/ui/search/search_delegate.h"
#include "chrome/browser/ui/search/search_model.h"
130
#include "chrome/browser/ui/search/search_tab_helper.h"
131
#include "chrome/browser/ui/settings_window_manager.h"
132
#include "chrome/browser/ui/singleton_tabs.h"
ben@chromium.org's avatar
Move:    
ben@chromium.org committed
133
#include "chrome/browser/ui/status_bubble.h"
134
#include "chrome/browser/ui/sync/browser_synced_window_delegate.h"
135
#include "chrome/browser/ui/tab_contents/core_tab_helper.h"
136
#include "chrome/browser/ui/tab_dialogs.h"
137
#include "chrome/browser/ui/tab_helpers.h"
138
#include "chrome/browser/ui/tab_modal_confirm_dialog.h"
ben@chromium.org's avatar
Move:    
ben@chromium.org committed
139
#include "chrome/browser/ui/tabs/tab_menu_model.h"
140
#include "chrome/browser/ui/tabs/tab_strip_model.h"
141
#include "chrome/browser/ui/tabs/tab_strip_model_utils.h"
142
#include "chrome/browser/ui/tabs/tab_utils.h"
143
#include "chrome/browser/ui/unload_controller.h"
144
#include "chrome/browser/ui/validation_message_bubble.h"
juncai's avatar
juncai committed
145
#include "chrome/browser/ui/website_settings/chooser_bubble_delegate.h"
146
#include "chrome/browser/ui/website_settings/permission_bubble_manager.h"
147
148
#include "chrome/browser/ui/webui/signin/login_ui_service.h"
#include "chrome/browser/ui/webui/signin/login_ui_service_factory.h"
149
#include "chrome/browser/ui/window_sizer/window_sizer.h"
150
#include "chrome/browser/upgrade_detector.h"
151
152
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_switches.h"
153
#include "chrome/common/custom_handlers/protocol_handler.h"
154
#include "chrome/common/pref_names.h"
155
#include "chrome/common/profiling.h"
156
#include "chrome/common/search_types.h"
157
#include "chrome/common/url_constants.h"
158
159
#include "chrome/grit/chromium_strings.h"
#include "chrome/grit/generated_resources.h"
160
#include "chrome/grit/locale_settings.h"
161
#include "components/app_modal/javascript_dialog_manager.h"
162
163
#include "components/bookmarks/browser/bookmark_model.h"
#include "components/bookmarks/browser/bookmark_utils.h"
164
#include "components/bookmarks/common/bookmark_pref_names.h"
165
#include "components/browser_sync/browser/profile_sync_service.h"
166
#include "components/bubble/bubble_controller.h"
167
#include "components/content_settings/core/browser/host_content_settings_map.h"
sdefresne's avatar
sdefresne committed
168
#include "components/favicon/content/content_favicon_driver.h"
169
#include "components/history/core/browser/top_sites.h"
brettw's avatar
brettw committed
170
#include "components/prefs/pref_service.h"
171
#include "components/search/search.h"
172
#include "components/security_state/security_state_model.h"
173
#include "components/sessions/core/session_types.h"
174
#include "components/sessions/core/tab_restore_service.h"
175
#include "components/startup_metric_utils/browser/startup_metric_utils.h"
176
#include "components/toolbar/toolbar_model_impl.h"
177
#include "components/translate/core/browser/language_state.h"
178
#include "components/web_modal/web_contents_modal_dialog_manager.h"
179
#include "components/zoom/zoom_controller.h"
180
#include "content/public/browser/devtools_agent_host.h"
181
#include "content/public/browser/interstitial_page.h"
182
#include "content/public/browser/invalidate_type.h"
183
#include "content/public/browser/navigation_controller.h"
184
#include "content/public/browser/navigation_entry.h"
185
186
#include "content/public/browser/notification_details.h"
#include "content/public/browser/notification_service.h"
187
#include "content/public/browser/plugin_service.h"
188
#include "content/public/browser/render_frame_host.h"
189
190
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h"
191
#include "content/public/browser/render_widget_host.h"
192
#include "content/public/browser/render_widget_host_view.h"
193
#include "content/public/browser/site_instance.h"
194
#include "content/public/browser/user_metrics.h"
195
#include "content/public/browser/web_contents.h"
196
#include "content/public/common/content_constants.h"
197
#include "content/public/common/content_switches.h"
csilv@chromium.org's avatar
csilv@chromium.org committed
198
#include "content/public/common/page_zoom.h"
199
#include "content/public/common/renderer_preferences.h"
200
#include "content/public/common/ssl_status.h"
201
#include "content/public/common/webplugininfo.h"
202
#include "extensions/browser/extension_prefs.h"
203
#include "extensions/browser/extension_registry.h"
204
#include "extensions/browser/extension_system.h"
205
#include "extensions/common/constants.h"
206
#include "extensions/common/extension.h"
207
#include "extensions/common/manifest_handlers/background_info.h"
208
#include "net/base/filename_util.h"
209
#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
210
#include "net/cookies/cookie_monster.h"
211
#include "net/url_request/url_request_context.h"
212
#include "third_party/WebKit/public/web/WebWindowFeatures.h"
ben@chromium.org's avatar
ben@chromium.org committed
213
#include "ui/base/l10n/l10n_util.h"
214
#include "ui/base/window_open_disposition.h"
215
#include "ui/gfx/geometry/point.h"
216
#include "ui/shell_dialogs/selected_file_info.h"
217
218

#if defined(OS_WIN)
219
220
#include <windows.h>
#include <shellapi.h>
ben@chromium.org's avatar
Move:    
ben@chromium.org committed
221
#include "chrome/browser/ui/view_ids.h"
222
#include "components/autofill/core/browser/autofill_ie_toolbar_import_win.h"
223
#include "ui/base/touch/touch_device.h"
224
#include "ui/base/win/shell.h"
225
#endif  // OS_WIN
226

227
#if defined(OS_CHROMEOS)
228
#include "chrome/browser/chromeos/fileapi/external_file_url_util.h"
229
230
#endif

231
#if defined(USE_ASH)
232
#include "ash/common/ash_switches.h"
233
#include "ash/shell.h"
234
235
#endif

236
using base::TimeDelta;
237
using base::UserMetricsAction;
238
using content::NativeWebKeyboardEvent;
239
using content::NavigationController;
240
using content::NavigationEntry;
241
using content::OpenURLParams;
242
using content::PluginService;
243
using content::Referrer;
244
using content::RenderWidgetHostView;
245
using content::SiteInstance;
246
using content::WebContents;
247
using extensions::Extension;
248
using security_state::SecurityStateModel;
249
using ui::WebDialogDelegate;
250
using web_modal::WebContentsModalDialogManager;
251
using blink::WebWindowFeatures;
initial.commit's avatar
initial.commit committed
252

253
254
255
///////////////////////////////////////////////////////////////////////////////

namespace {
initial.commit's avatar
initial.commit committed
256

257
258
// How long we wait before updating the browser chrome while loading a page.
const int kUIUpdateCoalescingTimeMS = 200;
initial.commit's avatar
initial.commit committed
259

260
261
262
263
BrowserWindow* CreateBrowserWindow(Browser* browser) {
  return BrowserWindow::CreateBrowserWindow(browser);
}

264
265
// Is the fast tab unload experiment enabled?
bool IsFastTabUnloadEnabled() {
266
267
  return base::CommandLine::ForCurrentProcess()->HasSwitch(
      switches::kEnableFastUnload);
268
269
}

ben@chromium.org's avatar
ben@chromium.org committed
270
271
}  // namespace

jianli@chromium.org's avatar
jianli@chromium.org committed
272
273
274
////////////////////////////////////////////////////////////////////////////////
// Browser, CreateParams:

275
Browser::CreateParams::CreateParams(Profile* profile)
276
    : type(TYPE_TABBED),
277
      profile(profile),
278
      trusted_source(false),
279
280
      initial_show_state(ui::SHOW_STATE_DEFAULT),
      is_session_restore(false),
281
      window(NULL) {}
282

283
Browser::CreateParams::CreateParams(Type type, Profile* profile)
284
285
    : type(type),
      profile(profile),
286
      trusted_source(false),
287
      initial_show_state(ui::SHOW_STATE_DEFAULT),
288
      is_session_restore(false),
289
      window(NULL) {}
jianli@chromium.org's avatar
jianli@chromium.org committed
290

291
292
Browser::CreateParams::CreateParams(const CreateParams& other) = default;

293
294
295
// static
Browser::CreateParams Browser::CreateParams::CreateForApp(
    const std::string& app_name,
296
    bool trusted_source,
297
    const gfx::Rect& window_bounds,
298
    Profile* profile) {
299
300
  DCHECK(!app_name.empty());

301
  CreateParams params(TYPE_POPUP, profile);
302
  params.app_name = app_name;
303
  params.trusted_source = trusted_source;
304
305
306
307
308
309
310
  params.initial_bounds = window_bounds;

  return params;
}

// static
Browser::CreateParams Browser::CreateParams::CreateForDevTools(
311
312
    Profile* profile) {
  CreateParams params(TYPE_POPUP, profile);
313
  params.app_name = DevToolsWindow::kDevToolsApp;
314
  params.trusted_source = true;
315
316
317
  return params;
}

318
319
320
321
322
323
324
325
326
327
////////////////////////////////////////////////////////////////////////////////
// Browser, InterstitialObserver:

class Browser::InterstitialObserver : public content::WebContentsObserver {
 public:
  InterstitialObserver(Browser* browser, content::WebContents* web_contents)
      : WebContentsObserver(web_contents),
        browser_(browser) {
  }

328
  void DidAttachInterstitialPage() override {
329
330
331
    browser_->UpdateBookmarkBarState(BOOKMARK_BAR_STATE_CHANGE_TAB_STATE);
  }

332
  void DidDetachInterstitialPage() override {
333
334
335
336
337
338
339
340
341
    browser_->UpdateBookmarkBarState(BOOKMARK_BAR_STATE_CHANGE_TAB_STATE);
  }

 private:
  Browser* browser_;

  DISALLOW_COPY_AND_ASSIGN(InterstitialObserver);
};

342
343
///////////////////////////////////////////////////////////////////////////////
// Browser, Constructors, Creation, Showing:
initial.commit's avatar
initial.commit committed
344

345
Browser::Browser(const CreateParams& params)
346
347
    : extension_registry_observer_(this),
      type_(params.type),
348
      profile_(params.profile),
349
      window_(NULL),
350
      tab_strip_model_delegate_(new chrome::BrowserTabStripModelDelegate(this)),
351
352
      tab_strip_model_(
          new TabStripModel(tab_strip_model_delegate_.get(), params.profile)),
353
      app_name_(params.app_name),
354
      is_trusted_source_(params.trusted_source),
355
      cancel_download_confirmation_state_(NOT_PROMPTED),
356
357
      override_bounds_(params.initial_bounds),
      initial_show_state_(params.initial_show_state),
358
      initial_workspace_(params.initial_workspace),
359
      is_session_restore_(params.is_session_restore),
360
361
362
      content_setting_bubble_model_delegate_(
          new BrowserContentSettingBubbleModelDelegate(this)),
      toolbar_model_delegate_(new BrowserToolbarModelDelegate(this)),
363
      live_tab_context_(new BrowserLiveTabContext(this)),
364
      synced_window_delegate_(new BrowserSyncedWindowDelegate(this)),
365
      bookmark_bar_state_(BookmarkBar::HIDDEN),
366
      command_controller_(new chrome::BrowserCommandController(this)),
367
      window_has_shown_(false),
368
      chrome_updater_factory_(this),
369
      weak_factory_(this) {
370
371
372
373
  // If this causes a crash then a window is being opened using a profile type
  // that is disallowed by policy. The crash prevents the disabled window type
  // from opening at all, but the path that triggered it should be fixed.
  CHECK(IncognitoModePrefs::CanOpenBrowser(profile_));
374
375
  CHECK(!profile_->IsGuestSession() || profile_->IsOffTheRecord())
      << "Only off the record browser may be opened in guest mode";
376
377
378
379
380
381
  DCHECK(!profile_->IsSystemProfile())
      << "The system profile should never have a real browser.";
  // TODO(mlerman): After this hits stable channel, see if there are counts
  // for this metric. If not, change the DCHECK above to a CHECK.
  if (profile_->IsSystemProfile())
    content::RecordAction(base::UserMetricsAction("BrowserForSystemProfile"));
382

383
384
385
386
387
388
  // TODO(jeremy): Move to initializer list once flag is removed.
  if (IsFastTabUnloadEnabled())
    fast_unload_controller_.reset(new chrome::FastUnloadController(this));
  else
    unload_controller_.reset(new chrome::UnloadController(this));

389
390
  tab_strip_model_->AddObserver(this);

391
392
  toolbar_model_.reset(new ToolbarModelImpl(toolbar_model_delegate_.get(),
                                            content::kMaxURLDisplayChars));
393
  search_model_.reset(new SearchModel());
394
  search_delegate_.reset(new SearchDelegate(search_model_.get()));
395

396
397
  extension_registry_observer_.Add(
      extensions::ExtensionRegistry::Get(profile_));
398
399
  registrar_.Add(this,
                 extensions::NOTIFICATION_EXTENSION_PROCESS_TERMINATED,
400
                 content::NotificationService::AllSources());
401
#if defined(ENABLE_THEMES)
402
  registrar_.Add(
403
      this, chrome::NOTIFICATION_BROWSER_THEME_CHANGED,
404
405
      content::Source<ThemeService>(
          ThemeServiceFactory::GetForProfile(profile_)));
406
#endif
407
  registrar_.Add(this, chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED,
408
                 content::NotificationService::AllSources());
initial.commit's avatar
initial.commit committed
409

410
  profile_pref_registrar_.Init(profile_->GetPrefs());
411
412
413
414
  profile_pref_registrar_.Add(
      prefs::kDevToolsDisabled,
      base::Bind(&Browser::OnDevToolsDisabledChanged, base::Unretained(this)));
  profile_pref_registrar_.Add(
415
      bookmarks::prefs::kShowBookmarkBar,
416
417
      base::Bind(&Browser::UpdateBookmarkBarState, base::Unretained(this),
                 BOOKMARK_BAR_STATE_CHANGE_PREF_CHANGE));
418

419
420
  // NOTE: These prefs all need to be explicitly destroyed in the destructor
  // or you'll get a nasty surprise when you run the incognito tests.
initial.commit's avatar
initial.commit committed
421
  encoding_auto_detect_.Init(prefs::kWebKitUsesUniversalDetector,
422
                             profile_->GetPrefs());
423

424
  if (search::IsInstantExtendedAPIEnabled() && is_type_tabbed())
425
    instant_controller_.reset(new BrowserInstantController(this));
426

427
428
429
  if (extensions::HostedAppBrowserController::IsForHostedApp(this)) {
    hosted_app_controller_.reset(
        new extensions::HostedAppBrowserController(this));
430
431
  }

432
  UpdateBookmarkBarState(BOOKMARK_BAR_STATE_CHANGE_INIT);
433

434
  ProfileMetrics::LogProfileLaunch(profile_);
435
436
437

  window_ = params.window ? params.window : CreateBrowserWindow(this);

438
439
  if (hosted_app_controller_)
    hosted_app_controller_->UpdateLocationBarVisibility(false);
440

441
442
443
444
  // Create the extension window controller before sending notifications.
  extension_window_controller_.reset(
      new BrowserExtensionWindowController(this));

445
446
447
448
449
  SessionService* session_service =
      SessionServiceFactory::GetForProfileForSessionRestore(profile_);
  if (session_service)
    session_service->WindowOpened(this);

450
  // TODO(beng): move to ChromeBrowserMain:
451
  if (first_run::ShouldDoPersonalDataManagerFirstRun()) {
452
#if defined(OS_WIN)
453
    // Notify PDM that this is a first run.
454
455
    ImportAutofillDataWin(
        autofill::PersonalDataManagerFactory::GetForProfile(profile_));
456
457
458
#endif  // defined(OS_WIN)
  }

459
460
  exclusive_access_manager_.reset(
      new ExclusiveAccessManager(window_->GetExclusiveAccessContext()));
461

462
463
464
465
466
467
  // TODO(beng): Move BrowserList::AddBrowser() to the end of this function and
  //             replace uses of this with BL's notifications.
  BrowserList::AddBrowser(this);
  content::NotificationService::current()->Notify(
      chrome::NOTIFICATION_BROWSER_WINDOW_READY, content::Source<Browser>(this),
      content::NotificationService::NoDetails());
initial.commit's avatar
initial.commit committed
468
469
470
}

Browser::~Browser() {
471
472
473
474
  // Stop observing notifications before continuing with destruction. Profile
  // destruction will unload extensions and reentrant calls to Browser:: should
  // be avoided while it is being torn down.
  registrar_.RemoveAll();
475
  extension_registry_observer_.RemoveAll();
476

477
  // The tab strip should not have any tabs at this point.
478
  DCHECK(tab_strip_model_->empty());
479
  tab_strip_model_->RemoveObserver(this);
480
  bubble_manager_.reset();
481

482
483
484
485
  // Destroy the BrowserCommandController before removing the browser, so that
  // it doesn't act on any notifications that are sent as a result of removing
  // the browser.
  command_controller_.reset();
initial.commit's avatar
initial.commit committed
486
487
  BrowserList::RemoveBrowser(this);

488
489
490
491
492
  SessionService* session_service =
      SessionServiceFactory::GetForProfile(profile_);
  if (session_service)
    session_service->WindowClosed(session_id_);

493
  sessions::TabRestoreService* tab_restore_service =
494
495
      TabRestoreServiceFactory::GetForProfile(profile());
  if (tab_restore_service)
496
    tab_restore_service->BrowserClosed(live_tab_context());
497

498
499
  profile_pref_registrar_.RemoveAll();

500
501
  encoding_auto_detect_.Destroy();

502
503
504
505
  // Destroy BrowserExtensionWindowController before the incognito profile
  // is destroyed to make sure the chrome.windows.onRemoved event is sent.
  extension_window_controller_.reset();

506
507
508
509
  // Destroy BrowserInstantController before the incongnito profile is destroyed
  // because the InstantController destructor depends on this profile.
  instant_controller_.reset();

initial.commit's avatar
initial.commit committed
510
  if (profile_->IsOffTheRecord() &&
511
      !BrowserList::IsOffTheRecordSessionActiveForProfile(profile_)) {
512
513
514
515
516
517
518
    if (profile_->IsGuestSession()) {
// ChromeOS handles guest data independently.
#if !defined(OS_CHROMEOS)
      // Clear all browsing data once a Guest Session completes. The Guest
      // profile has BrowserContextKeyedServices that the Incognito profile
      // doesn't, so the ProfileDestroyer can't delete it properly.
      // TODO(mlerman): Delete the guest using an improved ProfileDestroyer.
519
      profiles::RemoveBrowsingDataForProfile(profile_->GetPath());
520
521
522
523
524
525
#endif
    } else {
      // An incognito profile is no longer needed, this indirectly frees
      // its cache and cookies once it gets destroyed at the appropriate time.
      ProfileDestroyer::DestroyProfileWhenAppropriate(profile_);
    }
initial.commit's avatar
initial.commit committed
526
527
528
529
530
531
  }

  // There may be pending file dialogs, we need to tell them that we've gone
  // away so they don't try and call back to us.
  if (select_file_dialog_.get())
    select_file_dialog_->ListenerDestroyed();
532
533
534
535
536
537
538

  int num_downloads;
  if (OkToCloseWithInProgressDownloads(&num_downloads) ==
          DOWNLOAD_CLOSE_BROWSER_SHUTDOWN &&
      !browser_defaults::kBrowserAliveWithNoWindows) {
    DownloadService::CancelAllDownloads();
  }
initial.commit's avatar
initial.commit committed
539
540
}

541
542
543
///////////////////////////////////////////////////////////////////////////////
// Getters & Setters

544
545
546
547
548
549
ChromeBubbleManager* Browser::GetBubbleManager() {
  if (!bubble_manager_)
    bubble_manager_.reset(new ChromeBubbleManager(tab_strip_model_.get()));
  return bubble_manager_.get();
}

ben@chromium.org's avatar
ben@chromium.org committed
550
551
FindBarController* Browser::GetFindBarController() {
  if (!find_bar_controller_.get()) {
552
    FindBar* find_bar = window_->CreateFindBar();
ben@chromium.org's avatar
ben@chromium.org committed
553
554
    find_bar_controller_.reset(new FindBarController(find_bar));
    find_bar->SetFindBarController(find_bar_controller_.get());
555
556
    find_bar_controller_->ChangeWebContents(
        tab_strip_model_->GetActiveWebContents());
557
    find_bar_controller_->find_bar()->MoveWindowIfNecessary(gfx::Rect());
ben@chromium.org's avatar
ben@chromium.org committed
558
559
560
561
  }
  return find_bar_controller_.get();
}

562
563
564
565
bool Browser::HasFindBarController() const {
  return find_bar_controller_.get() != NULL;
}

jianli@chromium.org's avatar
jianli@chromium.org committed
566
567
568
569
570
571
572
573
bool Browser::is_app() const {
  return !app_name_.empty();
}

bool Browser::is_devtools() const {
  return app_name_ == DevToolsWindow::kDevToolsApp;
}

574
575
576
///////////////////////////////////////////////////////////////////////////////
// Browser, State Storage and Retrieval for UI:

577
gfx::Image Browser::GetCurrentPageIcon() const {
578
  WebContents* web_contents = tab_strip_model_->GetActiveWebContents();
579
580
  // |web_contents| can be NULL since GetCurrentPageIcon() is called by the
  // window during the window's creation (before tabs have been added).
sdefresne's avatar
sdefresne committed
581
582
583
584
585
  favicon::FaviconDriver* favicon_driver =
      web_contents
          ? favicon::ContentFaviconDriver::FromWebContents(web_contents)
          : nullptr;
  return favicon_driver ? favicon_driver->GetFavicon() : gfx::Image();
586
}
initial.commit's avatar
initial.commit committed
587

588
589
base::string16 Browser::GetWindowTitleForCurrentTab(
    bool include_app_name) const {
590
  WebContents* contents = tab_strip_model_->GetActiveWebContents();
591
  base::string16 title;
592

593
594
  // |contents| can be NULL because GetWindowTitleForCurrentTab is called by the
  // window during the window's creation (before tabs have been added).
595
  if (contents) {
596
597
    // The web app frame uses the host instead of the title.
    if (ShouldUseWebAppFrame())
598
599
      return base::UTF8ToUTF16(contents->GetURL().host());

600
    title = contents->GetTitle();
601
602
603
    FormatTitleForDisplay(&title);
  }
  if (title.empty())
604
    title = CoreTabHelper::GetDefaultTitle();
initial.commit's avatar
initial.commit committed
605

606
607
#if defined(OS_MACOSX)
  // On Mac, we don't want to suffix the page title with the application name.
davemoore@chromium.org's avatar
davemoore@chromium.org committed
608
  return title;
609
#endif
610
611
612
613
614
  // Include the app name in window titles for tabbed browser windows when
  // requested with |include_app_name|.
  return (!is_app() && include_app_name) ?
      l10n_util::GetStringFUTF16(IDS_BROWSER_WINDOW_TITLE_FORMAT, title):
      title;
615
}
initial.commit's avatar
initial.commit committed
616

617
// static
618
void Browser::FormatTitleForDisplay(base::string16* title) {
619
620
  size_t current_index = 0;
  size_t match_index;
621
622
623
  while ((match_index = title->find(L'\n', current_index)) !=
         base::string16::npos) {
    title->replace(match_index, 1, base::string16());
624
625
626
    current_index = match_index;
  }
}
initial.commit's avatar
initial.commit committed
627

628
629
///////////////////////////////////////////////////////////////////////////////
// Browser, OnBeforeUnload handling:
initial.commit's avatar
initial.commit committed
630

631
bool Browser::ShouldCloseWindow() {
632
633
634
  if (!CanCloseWithInProgressDownloads())
    return false;

635
636
  if (IsFastTabUnloadEnabled())
    return fast_unload_controller_->ShouldCloseWindow();
637
638
  return unload_controller_->ShouldCloseWindow();
}
initial.commit's avatar
initial.commit committed
639

640
641
bool Browser::CallBeforeUnloadHandlers(
    const base::Callback<void(bool)>& on_close_confirmed) {
642
  cancel_download_confirmation_state_ = RESPONSE_RECEIVED;
643
644
645
646
647
648
649
650
  if (IsFastTabUnloadEnabled()) {
    return fast_unload_controller_->CallBeforeUnloadHandlers(
        on_close_confirmed);
  }
  return unload_controller_->CallBeforeUnloadHandlers(on_close_confirmed);
}

void Browser::ResetBeforeUnloadHandlers() {
651
  cancel_download_confirmation_state_ = NOT_PROMPTED;
652
653
654
655
656
657
  if (IsFastTabUnloadEnabled())
    fast_unload_controller_->ResetBeforeUnloadHandlers();
  else
    unload_controller_->ResetBeforeUnloadHandlers();
}

658
659
660
661
662
bool Browser::HasCompletedUnloadProcessing() const {
  DCHECK(IsFastTabUnloadEnabled());
  return fast_unload_controller_->HasCompletedUnloadProcessing();
}

663
bool Browser::IsAttemptingToCloseBrowser() const {
664
665
  if (IsFastTabUnloadEnabled())
    return fast_unload_controller_->is_attempting_to_close_browser();
666
  return unload_controller_->is_attempting_to_close_browser();
667
668
}

669
670
671
672
673
674
675
676
677
678
679
680
681
682
bool Browser::ShouldRunUnloadListenerBeforeClosing(
    content::WebContents* web_contents) {
  if (IsFastTabUnloadEnabled())
    return fast_unload_controller_->ShouldRunUnloadEventsHelper(web_contents);
  return unload_controller_->ShouldRunUnloadEventsHelper(web_contents);
}

bool Browser::RunUnloadListenerBeforeClosing(
    content::WebContents* web_contents) {
  if (IsFastTabUnloadEnabled())
    return fast_unload_controller_->RunUnloadEventsHelper(web_contents);
  return unload_controller_->RunUnloadEventsHelper(web_contents);
}

683
684
685
686
void Browser::OnWindowClosing() {
  if (!ShouldCloseWindow())
    return;

687
688
689
690
691
  // Application should shutdown on last window close if the user is explicitly
  // trying to quit, or if there is nothing keeping the browser alive (such as
  // AppController on the Mac, or BackgroundContentsService for background
  // pages).
  bool should_quit_if_last_browser =
692
693
      browser_shutdown::IsTryingToQuit() ||
      !KeepAliveRegistry::GetInstance()->IsKeepingAlive();
694

695
  if (should_quit_if_last_browser && ShouldStartShutdown())
696
697
    browser_shutdown::OnShutdownStarting(browser_shutdown::WINDOW_CLOSE);

698
  // Don't use GetForProfileIfExisting here, we want to force creation of the
699
  // session service so that user can restore what was open.
700
701
  SessionService* session_service =
      SessionServiceFactory::GetForProfile(profile());
702
703
704
  if (session_service)
    session_service->WindowClosing(session_id());

705
  sessions::TabRestoreService* tab_restore_service =
706
      TabRestoreServiceFactory::GetForProfile(profile());
707
708

#if defined(USE_AURA)
709
  if (tab_restore_service && is_app() && !is_devtools())
710
    tab_restore_service->BrowserClosing(live_tab_context());
711
712
#endif

713
  if (tab_restore_service && is_type_tabbed() && tab_strip_model_->count())
714
    tab_restore_service->BrowserClosing(live_tab_context());
715

716
  // TODO(sky): convert session/tab restore to use notification.
717
  content::NotificationService::current()->Notify(
718
      chrome::NOTIFICATION_BROWSER_CLOSING,
719
      content::Source<Browser>(this),
720
      content::NotificationService::NoDetails());
721

722
723
  if (!IsFastTabUnloadEnabled())
    tab_strip_model_->CloseAllTabs();
724
725
}

726
727
728
729
730
731
////////////////////////////////////////////////////////////////////////////////
// In-progress download termination handling:

void Browser::InProgressDownloadResponse(bool cancel_downloads) {
  if (cancel_downloads) {
    cancel_download_confirmation_state_ = RESPONSE_RECEIVED;
732
    chrome::CloseWindow(this);
733
734
735
736
737
738
739
740
741
    return;
  }

  // Sets the confirmation state to NOT_PROMPTED so that if the user tries to
  // close again we'll show the warning again.
  cancel_download_confirmation_state_ = NOT_PROMPTED;

  // Show the download page so the user can figure-out what downloads are still
  // in-progress.
742
  chrome::ShowDownloads(this);
743
744
745
746
747
748
749

  // Reset UnloadController::is_attempting_to_close_browser_ so that we don't
  // prompt every time any tab is closed. http://crbug.com/305516
  if (IsFastTabUnloadEnabled())
    fast_unload_controller_->CancelWindowClose();
  else
    unload_controller_->CancelWindowClose();
750
751
}

752
753
754
755
756
757
758
759
760
761
Browser::DownloadClosePreventionType Browser::OkToCloseWithInProgressDownloads(
    int* num_downloads_blocking) const {
  DCHECK(num_downloads_blocking);
  *num_downloads_blocking = 0;

  // If we're not running a full browser process with a profile manager
  // (testing), it's ok to close the browser.
  if (!g_browser_process->profile_manager())
    return DOWNLOAD_CLOSE_OK;

762
763
  int total_download_count =
      DownloadService::NonMaliciousDownloadCountAllProfiles();
764
765
766
767
768
769
770
  if (total_download_count == 0)
    return DOWNLOAD_CLOSE_OK;   // No downloads; can definitely close.

  // Figure out how many windows are open total, and associated with this
  // profile, that are relevant for the ok-to-close decision.
  int profile_window_count = 0;
  int total_window_count = 0;
scottmg's avatar
scottmg committed
771
  for (auto* browser : *BrowserList::GetInstance()) {
772
    // Don't count this browser window or any other in the process of closing.
773
774
775
    // Window closing may be delayed, and windows that are in the process of
    // closing don't count against our totals.
    if (browser == this || browser->IsAttemptingToCloseBrowser())
776
777
      continue;

scottmg's avatar
scottmg committed
778
    if (browser->profile() == profile())
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
      profile_window_count++;
    total_window_count++;
  }

  // If there aren't any other windows, we're at browser shutdown,
  // which would cancel all current downloads.
  if (total_window_count == 0) {
    *num_downloads_blocking = total_download_count;
    return DOWNLOAD_CLOSE_BROWSER_SHUTDOWN;
  }

  // If there aren't any other windows on our profile, and we're an incognito
  // profile, and there are downloads associated with that profile,
  // those downloads would be cancelled by our window (-> profile) close.
  DownloadService* download_service =
794
      DownloadServiceFactory::GetForBrowserContext(profile());
795
  if ((profile_window_count == 0) &&
796
      (download_service->NonMaliciousDownloadCount() > 0) &&
797
      profile()->IsOffTheRecord()) {
798
    *num_downloads_blocking = download_service->NonMaliciousDownloadCount();
799
800
801
802
803
804
805
    return DOWNLOAD_CLOSE_LAST_WINDOW_IN_INCOGNITO_PROFILE;
  }

  // Those are the only conditions under which we will block shutdown.
  return DOWNLOAD_CLOSE_OK;
}

806
////////////////////////////////////////////////////////////////////////////////