Check USB device path access when prompting users to select a device.
[chromium-blink-merge.git] / chrome / browser / sessions / tab_loader.cc
blobdf77a8c906ede3d188c1aad804953c1fb78ba162
1 // Copyright 2015 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.
5 #include "chrome/browser/sessions/tab_loader.h"
7 #include <algorithm>
8 #include <string>
10 #include "base/metrics/histogram.h"
11 #include "base/strings/stringprintf.h"
12 #include "chrome/browser/ui/browser.h"
13 #include "chrome/browser/ui/browser_finder.h"
14 #include "chrome/browser/ui/tabs/tab_strip_model.h"
15 #include "content/public/browser/navigation_controller.h"
16 #include "content/public/browser/notification_service.h"
17 #include "content/public/browser/notification_types.h"
18 #include "content/public/browser/render_widget_host.h"
19 #include "content/public/browser/render_widget_host_view.h"
20 #include "content/public/browser/web_contents.h"
22 using content::NavigationController;
23 using content::RenderWidgetHost;
24 using content::WebContents;
26 void TabLoader::Observe(int type,
27 const content::NotificationSource& source,
28 const content::NotificationDetails& details) {
29 switch (type) {
30 case content::NOTIFICATION_WEB_CONTENTS_DESTROYED: {
31 WebContents* web_contents = content::Source<WebContents>(source).ptr();
32 HandleTabClosedOrLoaded(&web_contents->GetController());
33 break;
35 case content::NOTIFICATION_LOAD_STOP: {
36 NavigationController* controller =
37 content::Source<NavigationController>(source).ptr();
38 HandleTabClosedOrLoaded(controller);
39 break;
41 default:
42 NOTREACHED() << "Unknown notification received:" << type;
44 // Delete ourselves when we are done.
45 if (tabs_loading_.empty() && tabs_to_load_.empty())
46 this_retainer_ = nullptr;
49 void TabLoader::SetTabLoadingEnabled(bool enable_tab_loading) {
50 if (enable_tab_loading == loading_enabled_)
51 return;
52 loading_enabled_ = enable_tab_loading;
53 if (loading_enabled_)
54 LoadNextTab();
55 else
56 force_load_timer_.Stop();
59 // static
60 void TabLoader::RestoreTabs(const std::vector<RestoredTab>& tabs,
61 const base::TimeTicks& restore_started) {
62 if (!shared_tab_loader_)
63 shared_tab_loader_ = new TabLoader(restore_started);
65 shared_tab_loader_->StartLoading(tabs);
68 TabLoader::TabLoader(base::TimeTicks restore_started)
69 : memory_pressure_listener_(
70 base::Bind(&TabLoader::OnMemoryPressure, base::Unretained(this))),
71 force_load_delay_multiplier_(1),
72 loading_enabled_(true),
73 restore_started_(restore_started) {
74 shared_tab_loader_ = this;
75 this_retainer_ = this;
78 TabLoader::~TabLoader() {
79 DCHECK(tabs_loading_.empty() && tabs_to_load_.empty());
80 DCHECK(shared_tab_loader_ == this);
81 shared_tab_loader_ = nullptr;
84 void TabLoader::StartLoading(const std::vector<RestoredTab>& tabs) {
85 // Add the tabs to the list of tabs loading/to load and register them for
86 // notifications.
87 for (auto& restored_tab : tabs) {
88 if (!restored_tab.is_active)
89 tabs_to_load_.push_back(&restored_tab.contents->GetController());
90 else
91 tabs_loading_.insert(&restored_tab.contents->GetController());
92 RegisterForNotifications(&restored_tab.contents->GetController());
94 // When multiple profiles are using the same TabLoader, another profile might
95 // already have started loading. In that case, the tabs scheduled for loading
96 // by this profile are already in the loading queue, and they will get loaded
97 // eventually.
98 if (delegate_)
99 return;
101 // Create a TabLoaderDelegate which will allow OS specific behavior for tab
102 // loading.
103 if (!delegate_) {
104 delegate_ = TabLoaderDelegate::Create(this);
105 // There is already at least one tab loading (the active tab). As such we
106 // only have to start the timeout timer here.
107 StartTimer();
111 void TabLoader::LoadNextTab() {
112 // LoadNextTab should only get called after we have started the tab
113 // loading.
114 CHECK(delegate_);
115 if (!tabs_to_load_.empty()) {
116 NavigationController* controller = tabs_to_load_.front();
117 DCHECK(controller);
118 tabs_loading_.insert(controller);
119 tabs_to_load_.pop_front();
120 controller->LoadIfNecessary();
121 content::WebContents* contents = controller->GetWebContents();
122 if (contents) {
123 Browser* browser = chrome::FindBrowserWithWebContents(contents);
124 if (browser &&
125 browser->tab_strip_model()->GetActiveWebContents() != contents) {
126 // By default tabs are marked as visible. As only the active tab is
127 // visible we need to explicitly tell non-active tabs they are hidden.
128 // Without this call non-active tabs are not marked as backgrounded.
130 // NOTE: We need to do this here rather than when the tab is added to
131 // the Browser as at that time not everything has been created, so that
132 // the call would do nothing.
133 contents->WasHidden();
138 if (!tabs_to_load_.empty())
139 StartTimer();
142 void TabLoader::StartTimer() {
143 force_load_timer_.Stop();
144 force_load_timer_.Start(FROM_HERE,
145 delegate_->GetTimeoutBeforeLoadingNextTab() *
146 force_load_delay_multiplier_,
147 this, &TabLoader::ForceLoadTimerFired);
150 void TabLoader::RemoveTab(NavigationController* controller) {
151 registrar_.Remove(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
152 content::Source<WebContents>(controller->GetWebContents()));
153 registrar_.Remove(this, content::NOTIFICATION_LOAD_STOP,
154 content::Source<NavigationController>(controller));
156 TabsLoading::iterator i = tabs_loading_.find(controller);
157 if (i != tabs_loading_.end())
158 tabs_loading_.erase(i);
160 TabsToLoad::iterator j =
161 find(tabs_to_load_.begin(), tabs_to_load_.end(), controller);
162 if (j != tabs_to_load_.end())
163 tabs_to_load_.erase(j);
166 void TabLoader::ForceLoadTimerFired() {
167 force_load_delay_multiplier_ *= 2;
168 LoadNextTab();
171 void TabLoader::RegisterForNotifications(NavigationController* controller) {
172 registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
173 content::Source<WebContents>(controller->GetWebContents()));
174 registrar_.Add(this, content::NOTIFICATION_LOAD_STOP,
175 content::Source<NavigationController>(controller));
178 void TabLoader::HandleTabClosedOrLoaded(NavigationController* controller) {
179 RemoveTab(controller);
180 if (delegate_ && loading_enabled_)
181 LoadNextTab();
184 void TabLoader::OnMemoryPressure(
185 base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) {
186 // When receiving a resource pressure level warning, we stop pre-loading more
187 // tabs since we are running in danger of loading more tabs by throwing out
188 // old ones.
189 if (tabs_to_load_.empty())
190 return;
191 // Stop the timer and suppress any tab loads while we clean the list.
192 SetTabLoadingEnabled(false);
193 while (!tabs_to_load_.empty()) {
194 NavigationController* controller = tabs_to_load_.front();
195 tabs_to_load_.pop_front();
196 RemoveTab(controller);
198 // By calling |LoadNextTab| explicitly, we make sure that the
199 // |NOTIFICATION_SESSION_RESTORE_DONE| event gets sent.
200 LoadNextTab();
203 // static
204 TabLoader* TabLoader::shared_tab_loader_ = nullptr;