Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(630)

Side by Side Diff: chrome/browser/android/offline_pages/recent_tab_helper.cc

Issue 2092983002: Change the RecentTabHelper to only capture the last one page in a tab. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: removed unused variable Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2016 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/android/offline_pages/recent_tab_helper.h" 5 #include "chrome/browser/android/offline_pages/recent_tab_helper.h"
6 6
7 #include <queue> 7 #include <queue>
8 #include <vector> 8 #include <vector>
9 9
10 #include "base/bind.h" 10 #include "base/bind.h"
11 #include "base/location.h" 11 #include "base/location.h"
12 #include "base/logging.h"
13 #include "base/macros.h" 12 #include "base/macros.h"
13 #include "base/memory/ptr_util.h"
14 #include "base/metrics/histogram_macros.h" 14 #include "base/metrics/histogram_macros.h"
15 #include "base/strings/string_number_conversions.h"
15 #include "base/threading/thread_task_runner_handle.h" 16 #include "base/threading/thread_task_runner_handle.h"
16 #include "base/time/time.h" 17 #include "base/time/time.h"
17 #include "chrome/browser/android/offline_pages/offline_page_mhtml_archiver.h" 18 #include "chrome/browser/android/offline_pages/offline_page_mhtml_archiver.h"
18 #include "chrome/browser/android/offline_pages/offline_page_model_factory.h" 19 #include "chrome/browser/android/offline_pages/offline_page_model_factory.h"
20 #include "chrome/browser/android/tab_android.h"
19 #include "components/offline_pages/client_namespace_constants.h" 21 #include "components/offline_pages/client_namespace_constants.h"
20 #include "components/offline_pages/offline_page_item.h" 22 #include "components/offline_pages/offline_page_item.h"
21 #include "components/offline_pages/offline_page_model.h" 23 #include "components/offline_pages/offline_page_model.h"
22 #include "content/public/browser/browser_context.h" 24 #include "content/public/browser/browser_context.h"
23 #include "content/public/browser/browser_thread.h" 25 #include "content/public/browser/browser_thread.h"
24 #include "content/public/browser/navigation_entry.h" 26 #include "content/public/browser/navigation_entry.h"
25 #include "content/public/browser/navigation_handle.h" 27 #include "content/public/browser/navigation_handle.h"
26 28
27 DEFINE_WEB_CONTENTS_USER_DATA_KEY(offline_pages::RecentTabHelper); 29 DEFINE_WEB_CONTENTS_USER_DATA_KEY(offline_pages::RecentTabHelper);
28 30
29 namespace { 31 namespace {
32 class DefaultDelegate: public offline_pages::RecentTabHelper::Delegate {
33 public:
34 DefaultDelegate() {}
30 35
31 // Max number of pages to keep. The oldest pages that are over this count are 36 // offline_pages::RecentTabHelper::Delegate
32 // deleted before the next one is saved. 37 std::unique_ptr<offline_pages::OfflinePageArchiver> CreatePageArchiver(
33 const size_t kMaxPagesToKeep = 50; 38 content::WebContents* web_contents) override {
34 39 return base::MakeUnique<offline_pages::OfflinePageMHTMLArchiver>(
35 // Predicate for priority_queue used to compute the oldest pages. 40 web_contents);
36 struct ComparePagesForPurge { 41 }
37 bool operator()(const offline_pages::OfflinePageItem* left, 42 scoped_refptr<base::SingleThreadTaskRunner> GetTaskRunner() override {
38 const offline_pages::OfflinePageItem* right) const { 43 return base::ThreadTaskRunnerHandle::Get();
39 return left->creation_time > right->creation_time; 44 }
45 bool GetTabId(content::WebContents* web_contents, int* tab_id) override {
46 TabAndroid* tab_android = TabAndroid::FromWebContents(web_contents);
47 if (!tab_android)
48 return false;
49 *tab_id = tab_android->GetAndroidId();
50 return true;
40 } 51 }
41 }; 52 };
42
43 } // namespace 53 } // namespace
44 54
45 namespace offline_pages { 55 namespace offline_pages {
46 56
47 RecentTabHelper::RecentTabHelper(content::WebContents* web_contents) 57 RecentTabHelper::RecentTabHelper(content::WebContents* web_contents)
48 : content::WebContentsObserver(web_contents), 58 : content::WebContentsObserver(web_contents),
49 page_model_(nullptr), 59 page_model_(nullptr),
60 delegate_(new DefaultDelegate()),
50 weak_ptr_factory_(this) { 61 weak_ptr_factory_(this) {
51 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 62 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
52 snapshot_controller_.reset(new SnapshotController(
53 base::ThreadTaskRunnerHandle::Get(), this));
54 page_model_ = OfflinePageModelFactory::GetForBrowserContext(
55 web_contents->GetBrowserContext());
56
57 // TODO(dimich): When we have BackgroundOffliner, avoid capturing prerenderer
58 // WebContents with its origin as well.
59 never_do_snapshots_ = web_contents->GetBrowserContext()->IsOffTheRecord();
60 } 63 }
61 64
62 RecentTabHelper::~RecentTabHelper() { 65 RecentTabHelper::~RecentTabHelper() {
63 } 66 }
64 67
68 void RecentTabHelper::SetDelegate(
69 std::unique_ptr<RecentTabHelper::Delegate> delegate) {
70 DCHECK(delegate);
71 delegate_ = std::move(delegate);
72 }
73
74 void RecentTabHelper::LazyInitialize() {
75 snapshot_controller_.reset(new SnapshotController(delegate_->GetTaskRunner(),
76 this));
77 int tab_id_number = 0;
78 tab_id_.clear();
79
80 if (delegate_->GetTabId(web_contents(), &tab_id_number))
81 tab_id_ = base::IntToString(tab_id_number);
82
83 page_model_ = OfflinePageModelFactory::GetForBrowserContext(
84 web_contents()->GetBrowserContext());
85
86 // TODO(dimich): When we have BackgroundOffliner, avoid capturing prerenderer
87 // WebContents with its origin as well.
88 never_do_snapshots_ = tab_id_.empty() ||
89 web_contents()->GetBrowserContext()->IsOffTheRecord();
90 }
91
65 void RecentTabHelper::DidFinishNavigation( 92 void RecentTabHelper::DidFinishNavigation(
66 content::NavigationHandle* navigation_handle) { 93 content::NavigationHandle* navigation_handle) {
94 // Initialize lazily. It needs TabAndroid for initization, which is also a
95 // TabHelper - so can't initialize in constructor because of uncertain order
96 // of creation of TabHelpers.
97 if (!snapshot_controller_)
98 LazyInitialize();
99
67 if (navigation_handle->IsInMainFrame() && 100 if (navigation_handle->IsInMainFrame() &&
68 navigation_handle->HasCommitted()) { 101 navigation_handle->HasCommitted()) {
69 // Cancel tasks in flight that relate to the previous page. 102 // Cancel tasks in flight that relate to the previous page.
70 weak_ptr_factory_.InvalidateWeakPtrs(); 103 weak_ptr_factory_.InvalidateWeakPtrs();
71 104
72 // New navigation, new snapshot session. 105 // New navigation, new snapshot session.
73 snapshot_url_ = GURL(); 106 snapshot_url_ = GURL();
74 GURL last_committed_url = web_contents()->GetLastCommittedURL(); 107 GURL last_committed_url = web_contents()->GetLastCommittedURL();
75 108
76 // Check for conditions that would cause us not to snapshot. 109 // Check for conditions that would cause us not to snapshot.
(...skipping 22 matching lines...) Expand all
99 snapshot_controller_->DocumentOnLoadCompletedInMainFrame(); 132 snapshot_controller_->DocumentOnLoadCompletedInMainFrame();
100 } 133 }
101 134
102 // This starts a sequence of async operations chained through callbacks: 135 // This starts a sequence of async operations chained through callbacks:
103 // - compute the set of old 'last_n' pages that have to be purged 136 // - compute the set of old 'last_n' pages that have to be purged
104 // - delete the pages found in the previous step 137 // - delete the pages found in the previous step
105 // - snapshot the current web contents 138 // - snapshot the current web contents
106 // Along the chain, the original URL is passed and compared, to detect 139 // Along the chain, the original URL is passed and compared, to detect
107 // possible navigation and cancel snapshot in that case. 140 // possible navigation and cancel snapshot in that case.
108 void RecentTabHelper::StartSnapshot() { 141 void RecentTabHelper::StartSnapshot() {
109 // TODO(dimich): Implement automatic cleanup as per design doc, based on 142 // Remove previously captured pages for this tab.
110 // storage limits and page age.
111 // This algorithm (remove pages before making sure the save was successful)
112 // prefers keeping the storage use low and under control by potentially
113 // sacrificing the current snapshot.
114 page_model_->GetOfflineIdsForClientId( 143 page_model_->GetOfflineIdsForClientId(
115 client_id(), 144 client_id(),
116 base::Bind(&RecentTabHelper::ContinueSnapshotWithIdsToPurge, 145 base::Bind(&RecentTabHelper::ContinueSnapshotWithIdsToPurge,
117 weak_ptr_factory_.GetWeakPtr())); 146 weak_ptr_factory_.GetWeakPtr()));
118 } 147 }
119 148
120 // Collects following pages from lastN namespace:
121 // - the ones with the same online URL
122 // - the oldest pages, enough to keep kMaxPagesToKeep limit.
123 void RecentTabHelper::ContinueSnapshotWithIdsToPurge( 149 void RecentTabHelper::ContinueSnapshotWithIdsToPurge(
124 const std::vector<int64_t>& page_ids) { 150 const std::vector<int64_t>& page_ids) {
125
126 std::vector<int64_t> pages_to_purge;
127 // Use priority queue to figure out the set of oldest pages to purge.
128 std::priority_queue<const OfflinePageItem*,
129 std::vector<const OfflinePageItem*>,
130 ComparePagesForPurge> pages_queue;
131
132 for (const auto& offline_id : page_ids) {
133 // TODO(dimich): get rid of 'Maybe'. Maybe make it return multiple pages.
134 const OfflinePageItem* page =
135 page_model_->MaybeGetPageByOfflineId(offline_id);
136 // If there is already a snapshot of this page, remove it so we don't
137 // have multiple snapshots of the same page.
138 if (page->url == snapshot_url_) {
139 pages_to_purge.push_back(offline_id);
140 } else {
141 pages_queue.push(page);
142 }
143 }
144
145 // Negative counter means nothing else to purge.
146 int count_to_purge =
147 page_ids.size() - kMaxPagesToKeep - pages_to_purge.size();
148
149 for (int count = 0; count < count_to_purge; ++count) {
150 pages_to_purge.push_back(pages_queue.top()->offline_id);
151 pages_queue.pop();
152 }
153
154 page_model_->DeletePagesByOfflineId( 151 page_model_->DeletePagesByOfflineId(
155 pages_to_purge, base::Bind(&RecentTabHelper::ContinueSnapshotAfterPurge, 152 page_ids, base::Bind(&RecentTabHelper::ContinueSnapshotAfterPurge,
156 weak_ptr_factory_.GetWeakPtr())); 153 weak_ptr_factory_.GetWeakPtr()));
157 } 154 }
158 155
159 void RecentTabHelper::ContinueSnapshotAfterPurge( 156 void RecentTabHelper::ContinueSnapshotAfterPurge(
160 OfflinePageModel::DeletePageResult result) { 157 OfflinePageModel::DeletePageResult result) {
161 if (result != OfflinePageModel::DeletePageResult::SUCCESS) { 158 if (result != OfflinePageModel::DeletePageResult::SUCCESS) {
162 // If previous pages can't be deleted, don't add new ones. 159 // If previous pages can't be deleted, don't add new ones.
163 ReportSnapshotCompleted(); 160 ReportSnapshotCompleted();
164 return; 161 return;
165 } 162 }
166 163
167 if (!IsSamePage()) { 164 if (!IsSamePage()) {
168 ReportSnapshotCompleted(); 165 ReportSnapshotCompleted();
169 return; 166 return;
170 } 167 }
171 168
172 // Create either test Archiver or a regular one.
173 std::unique_ptr<OfflinePageArchiver> archiver;
174 if (test_archive_factory_.get()) {
175 archiver = test_archive_factory_->CreateArchiver(web_contents());
176 } else {
177 archiver.reset(new OfflinePageMHTMLArchiver(web_contents()));
178 }
179
180 page_model_->SavePage( 169 page_model_->SavePage(
181 snapshot_url_, client_id(), std::move(archiver), 170 snapshot_url_, client_id(),
171 delegate_->CreatePageArchiver(web_contents()),
182 base::Bind(&RecentTabHelper::SavePageCallback, 172 base::Bind(&RecentTabHelper::SavePageCallback,
183 weak_ptr_factory_.GetWeakPtr())); 173 weak_ptr_factory_.GetWeakPtr()));
184 } 174 }
185 175
186 void RecentTabHelper::SavePageCallback(OfflinePageModel::SavePageResult result, 176 void RecentTabHelper::SavePageCallback(OfflinePageModel::SavePageResult result,
187 int64_t offline_id) { 177 int64_t offline_id) {
188 ReportSnapshotCompleted(); 178 ReportSnapshotCompleted();
189 } 179 }
190 180
191 void RecentTabHelper::ReportSnapshotCompleted() { 181 void RecentTabHelper::ReportSnapshotCompleted() {
192 snapshot_controller_->PendingSnapshotCompleted(); 182 snapshot_controller_->PendingSnapshotCompleted();
193 } 183 }
194 184
195 bool RecentTabHelper::IsSamePage() const { 185 bool RecentTabHelper::IsSamePage() const {
196 return web_contents() && 186 return web_contents() &&
197 (web_contents()->GetLastCommittedURL() == snapshot_url_); 187 (web_contents()->GetLastCommittedURL() == snapshot_url_);
198 } 188 }
199 189
200 ClientId RecentTabHelper::client_id() const { 190 ClientId RecentTabHelper::client_id() const {
201 return ClientId(kLastNNamespace, ""); 191 return ClientId(kLastNNamespace, tab_id_);
202 }
203
204 void RecentTabHelper::SetArchiveFactoryForTest(
205 std::unique_ptr<TestArchiveFactory> test_archive_factory) {
206 test_archive_factory_ = std::move(test_archive_factory);
207 }
208
209 void RecentTabHelper::SetTaskRunnerForTest(
210 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) {
211 snapshot_controller_.reset(new SnapshotController(task_runner, this));
212 } 192 }
213 193
214 } // namespace offline_pages 194 } // namespace offline_pages
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698