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

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

Issue 1936613002: Implementing recent pages snapshot capture. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: clang is my friend Created 4 years, 7 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>
8 #include <vector>
9
10 #include "base/bind.h"
11 #include "base/location.h"
12 #include "base/logging.h"
13 #include "base/macros.h"
14 #include "base/thread_task_runner_handle.h"
15 #include "base/time/time.h"
16 #include "chrome/browser/android/offline_pages/offline_page_mhtml_archiver.h"
17 #include "chrome/browser/android/offline_pages/offline_page_model_factory.h"
18 #include "components/offline_pages/offline_page_item.h"
19 #include "components/offline_pages/offline_page_model.h"
20 #include "content/public/browser/browser_context.h"
21 #include "content/public/browser/browser_thread.h"
22 #include "content/public/browser/navigation_entry.h"
23 #include "content/public/browser/navigation_handle.h"
24
7 DEFINE_WEB_CONTENTS_USER_DATA_KEY(offline_pages::RecentTabHelper); 25 DEFINE_WEB_CONTENTS_USER_DATA_KEY(offline_pages::RecentTabHelper);
8 26
27 namespace {
28 const char* kClientNamespace = "last_n";
29
30 // Max number of pages to keep. The oldest pages that are over this count are
31 // deleted before the next one is saved.
32 const size_t kMaxPagesToKeep = 50;
33
34 // Predicate for priority_queue used to compute the oldest pages.
35 struct ComparePagesForPurge {
36 bool operator()(const offline_pages::OfflinePageItem* left,
37 const offline_pages::OfflinePageItem* right) const {
38 return left->creation_time > right->creation_time;
39 }
40 };
41
42 } // namespace
43
9 namespace offline_pages { 44 namespace offline_pages {
10 45
11 RecentTabHelper::RecentTabHelper(content::WebContents* web_contents) 46 RecentTabHelper::RecentTabHelper(content::WebContents* web_contents)
12 : content::WebContentsObserver(web_contents) { 47 : content::WebContentsObserver(web_contents),
48 page_model_(nullptr),
49 weak_ptr_factory_(this) {
50 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
51 snapshot_controller_.reset(new SnapshotController(
52 base::ThreadTaskRunnerHandle::Get(), this));
53 page_model_ = OfflinePageModelFactory::GetForBrowserContext(
54 web_contents->GetBrowserContext());
55
56 // TODO(dimich): When we have BackgroundOffliner, avoid capturing prerenderer
57 // WebContents with its origin as well.
58 never_do_snapshots_ = web_contents->GetBrowserContext()->IsOffTheRecord();
13 } 59 }
14 60
15 RecentTabHelper::~RecentTabHelper() { 61 RecentTabHelper::~RecentTabHelper() {
16 } 62 }
17 63
64 void RecentTabHelper::DidFinishNavigation(
65 content::NavigationHandle* navigation_handle) {
66 if (navigation_handle->IsInMainFrame() &&
67 navigation_handle->HasCommitted() &&
68 !navigation_handle->IsErrorPage()) {
69 // New navigation, new snapshot session.
70 snapshot_controller_->Reset();
71 snapshot_url_ = GURL::EmptyGURL();
72 }
73 }
74
75 void RecentTabHelper::DocumentAvailableInMainFrame() {
76 snapshot_controller_->DocumentAvailableInMainFrame();
77 }
78
79 void RecentTabHelper::DocumentOnLoadCompletedInMainFrame() {
80 snapshot_controller_->DocumentOnLoadCompletedInMainFrame();
81 }
82
83 // This starts a sequence of async operations chained through callbacks:
84 // - compute the set of old 'last_n' pages that have to be purged
85 // - delete the pages found in the previous step
86 // - snapshot the current web contents
87 // Along the chain, the original URL is passed and compared, to detect
88 // possible navigation and cancel snapshot in that case.
89 void RecentTabHelper::StartSnapshot() {
90 if (never_do_snapshots_)
91 return;
92
93 GURL url = web_contents()->GetLastCommittedURL();
94 if (!page_model_->CanSavePage(url)) {
95 // TODO(dimich): Add UMA. Bug 608112.
96 return;
97 }
98
99 snapshot_url_ = url;
100
101 // TODO(dimich): Implement automatic cleanup as per design doc, based on
102 // storage limits and page age.
103 // This algorithm (remove pages before making sure the save was successful)
104 // prefers keeping the storage use low and under control by potentially
105 // sacrificing the current snapshot.
106 page_model_->GetOfflineIdsForClientId(
107 client_id(),
108 base::Bind(&RecentTabHelper::ContinueSnapshotWithIdsToPurge,
109 weak_ptr_factory_.GetWeakPtr()));
110 }
111
112 // Collects following pages from lastN namespace:
113 // - the ones with the same online URL
114 // - the oldest pages, enough to keep kMaxPagesToKeep limit.
115 void RecentTabHelper::ContinueSnapshotWithIdsToPurge(
116 const std::vector<int64_t>& page_ids) {
117
118 std::vector<int64_t> pages_to_purge;
119 // Use priority queue to figure out the set of oldest pages to purge.
120 std::priority_queue<const OfflinePageItem*,
121 std::vector<const OfflinePageItem*>,
122 ComparePagesForPurge> pages_queue;
123
124 for (const auto& offline_id : page_ids) {
125 // TODO(dimich): get rid of 'Maybe'. Maybe make it return multiple pages.
126 const OfflinePageItem* page =
127 page_model_->MaybeGetPageByOfflineId(offline_id);
128 // If there is already a snapshot of this page, remove it so we don't
129 // have multiple snapshots of the same page.
130 if (page->url == snapshot_url_) {
131 pages_to_purge.push_back(offline_id);
132 } else {
133 pages_queue.push(page);
134 }
135 }
136
137 // Negative counter means nothing else to purge.
138 int count_to_purge =
139 page_ids.size() - kMaxPagesToKeep - pages_to_purge.size();
140
141 for (int count = 0; count < count_to_purge; ++count) {
142 pages_to_purge.push_back(pages_queue.top()->offline_id);
143 pages_queue.pop();
144 }
145
146 page_model_->DeletePagesByOfflineId(
147 pages_to_purge, base::Bind(&RecentTabHelper::ContinueSnapshotAfterPurge,
148 weak_ptr_factory_.GetWeakPtr()));
149 }
150
151 void RecentTabHelper::ContinueSnapshotAfterPurge(
152 OfflinePageModel::DeletePageResult result) {
153 // NOT_FOUND is because it's what we get when passing empty vector of ids.
154 // TODO(dimich): remove NOT_FOUND when bug 608057 is fixed.
155 if (result != OfflinePageModel::DeletePageResult::SUCCESS &&
156 result != OfflinePageModel::DeletePageResult::NOT_FOUND) {
157 // If previous pages can't be deleted, don't add new ones.
158 ReportSnapshotCompleted();
159 return;
160 }
161
162 if (!IsSamePage()) {
163 ReportSnapshotCompleted();
164 return;
165 }
166
167 // Create either test Archiver or a regular one.
168 std::unique_ptr<OfflinePageArchiver> archiver;
169 if (test_archive_factory_.get()) {
170 archiver = test_archive_factory_->CreateArchiver(web_contents());
171 } else {
172 archiver.reset(new OfflinePageMHTMLArchiver(web_contents()));
173 }
174
175 page_model_->SavePage(
176 snapshot_url_, client_id(), std::move(archiver),
177 base::Bind(&RecentTabHelper::SavePageCallback,
178 weak_ptr_factory_.GetWeakPtr()));
179 }
180
181 void RecentTabHelper::SavePageCallback(OfflinePageModel::SavePageResult result,
182 int64_t offline_id) {
183 // TODO(dimich): add UMA, including result. Bug 608112.
184 ReportSnapshotCompleted();
185 }
186
187 void RecentTabHelper::ReportSnapshotCompleted() {
188 snapshot_controller_->PendingSnapshotCompleted();
189 }
190
191 bool RecentTabHelper::IsSamePage() const {
192 return web_contents() &&
193 (web_contents()->GetLastCommittedURL() == snapshot_url_);
194 }
195
196 ClientId RecentTabHelper::client_id() const {
197 return ClientId(kClientNamespace, "");
198 }
199
200 void RecentTabHelper::SetArchiveFactoryForTest(
201 std::unique_ptr<TestArchiveFactory> test_archive_factory) {
202 test_archive_factory_ = std::move(test_archive_factory);
203 }
204
205 void RecentTabHelper::SetTaskRunnerForTest(
206 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) {
207 snapshot_controller_.reset(new SnapshotController(task_runner, this));
208 }
209
18 } // namespace offline_pages 210 } // namespace offline_pages
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698