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

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: added unittests, process 'no id' case Created 4 years, 6 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"
14 #include "base/metrics/histogram_macros.h" 13 #include "base/metrics/histogram_macros.h"
14 #include "base/strings/string_number_conversions.h"
15 #include "base/threading/thread_task_runner_handle.h" 15 #include "base/threading/thread_task_runner_handle.h"
16 #include "base/time/time.h" 16 #include "base/time/time.h"
17 #include "chrome/browser/android/offline_pages/offline_page_mhtml_archiver.h" 17 #include "chrome/browser/android/offline_pages/offline_page_mhtml_archiver.h"
18 #include "chrome/browser/android/offline_pages/offline_page_model_factory.h" 18 #include "chrome/browser/android/offline_pages/offline_page_model_factory.h"
19 #include "chrome/browser/android/tab_android.h"
19 #include "components/offline_pages/client_namespace_constants.h" 20 #include "components/offline_pages/client_namespace_constants.h"
20 #include "components/offline_pages/offline_page_item.h" 21 #include "components/offline_pages/offline_page_item.h"
21 #include "components/offline_pages/offline_page_model.h" 22 #include "components/offline_pages/offline_page_model.h"
22 #include "content/public/browser/browser_context.h" 23 #include "content/public/browser/browser_context.h"
23 #include "content/public/browser/browser_thread.h" 24 #include "content/public/browser/browser_thread.h"
24 #include "content/public/browser/navigation_entry.h" 25 #include "content/public/browser/navigation_entry.h"
25 #include "content/public/browser/navigation_handle.h" 26 #include "content/public/browser/navigation_handle.h"
26 27
27 DEFINE_WEB_CONTENTS_USER_DATA_KEY(offline_pages::RecentTabHelper); 28 DEFINE_WEB_CONTENTS_USER_DATA_KEY(offline_pages::RecentTabHelper);
28 29
29 namespace { 30 namespace {
31 class DefaultDelegate: public offline_pages::RecentTabHelper::Delegate {
32 public:
33 DefaultDelegate() {}
30 34
31 // Max number of pages to keep. The oldest pages that are over this count are 35 // offline_pages::RecentTabHelper::Delegate
32 // deleted before the next one is saved. 36 std::unique_ptr<offline_pages::OfflinePageArchiver> CreatePageArchiver(
33 const size_t kMaxPagesToKeep = 50; 37 content::WebContents* web_contents) override {
34 38 std::unique_ptr<offline_pages::OfflinePageArchiver> archiver(
35 // Predicate for priority_queue used to compute the oldest pages. 39 new offline_pages::OfflinePageMHTMLArchiver(web_contents));
36 struct ComparePagesForPurge { 40 return archiver;
dewittj 2016/06/24 23:10:33 nit: return base::MakeUnique<offline_pages::Offine
Dmitry Titov 2016/06/24 23:58:01 Done.
37 bool operator()(const offline_pages::OfflinePageItem* left, 41 }
38 const offline_pages::OfflinePageItem* right) const { 42 scoped_refptr<base::SingleThreadTaskRunner> GetTaskRunner() override {
39 return left->creation_time > right->creation_time; 43 return base::ThreadTaskRunnerHandle::Get();
44 }
45 bool GetTabId(int* tab_id, content::WebContents* web_contents) override {
dewittj 2016/06/24 23:10:33 nit: outparams usually go after inparams in my exp
Dmitry Titov 2016/06/24 23:58:01 Done. Not Optional...
46 *tab_id = 0;
dewittj 2016/06/24 23:10:33 nit: don't set tab_id on failure.
Dmitry Titov 2016/06/24 23:58:01 Done.
47 TabAndroid* tab_android = TabAndroid::FromWebContents(web_contents);
48 if (!tab_android)
49 return false;
50 *tab_id = tab_android->GetAndroidId();
51 return true;
40 } 52 }
41 }; 53 };
42
43 } // namespace 54 } // namespace
44 55
45 namespace offline_pages { 56 namespace offline_pages {
46 57
47 RecentTabHelper::RecentTabHelper(content::WebContents* web_contents) 58 RecentTabHelper::RecentTabHelper(content::WebContents* web_contents)
48 : content::WebContentsObserver(web_contents), 59 : content::WebContentsObserver(web_contents),
49 page_model_(nullptr), 60 page_model_(nullptr),
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( 63 Initialize(std::unique_ptr<DefaultDelegate>(new DefaultDelegate()));
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 } 64 }
61 65
62 RecentTabHelper::~RecentTabHelper() { 66 RecentTabHelper::~RecentTabHelper() {
63 } 67 }
64 68
69 void RecentTabHelper::Initialize(
70 std::unique_ptr<RecentTabHelper::Delegate> delegate) {
71 DCHECK(delegate.get());
dewittj 2016/06/24 23:10:33 I think you can just use the boolean conversion: D
Dmitry Titov 2016/06/24 23:58:01 Done.
72 delegate_ = std::move(delegate);
73 snapshot_controller_.reset(new SnapshotController(delegate_->GetTaskRunner(),
74 this));
75 int tab_id_number = 0;
76 if (delegate_->GetTabId(&tab_id_number, web_contents()))
77 tab_id_ = base::IntToString(tab_id_number);
78 else
79 tab_id_.clear();
80
81 page_model_ = OfflinePageModelFactory::GetForBrowserContext(
82 web_contents()->GetBrowserContext());
83
84 // TODO(dimich): When we have BackgroundOffliner, avoid capturing prerenderer
85 // WebContents with its origin as well.
86 never_do_snapshots_ = tab_id_.empty() ||
87 web_contents()->GetBrowserContext()->IsOffTheRecord();
88 }
89
65 void RecentTabHelper::DidFinishNavigation( 90 void RecentTabHelper::DidFinishNavigation(
66 content::NavigationHandle* navigation_handle) { 91 content::NavigationHandle* navigation_handle) {
67 if (navigation_handle->IsInMainFrame() && 92 if (navigation_handle->IsInMainFrame() &&
68 navigation_handle->HasCommitted()) { 93 navigation_handle->HasCommitted()) {
69 // Cancel tasks in flight that relate to the previous page. 94 // Cancel tasks in flight that relate to the previous page.
70 weak_ptr_factory_.InvalidateWeakPtrs(); 95 weak_ptr_factory_.InvalidateWeakPtrs();
71 96
72 // New navigation, new snapshot session. 97 // New navigation, new snapshot session.
73 snapshot_url_ = GURL(); 98 snapshot_url_ = GURL();
74 GURL last_committed_url = web_contents()->GetLastCommittedURL(); 99 GURL last_committed_url = web_contents()->GetLastCommittedURL();
(...skipping 24 matching lines...) Expand all
99 snapshot_controller_->DocumentOnLoadCompletedInMainFrame(); 124 snapshot_controller_->DocumentOnLoadCompletedInMainFrame();
100 } 125 }
101 126
102 // This starts a sequence of async operations chained through callbacks: 127 // This starts a sequence of async operations chained through callbacks:
103 // - compute the set of old 'last_n' pages that have to be purged 128 // - compute the set of old 'last_n' pages that have to be purged
104 // - delete the pages found in the previous step 129 // - delete the pages found in the previous step
105 // - snapshot the current web contents 130 // - snapshot the current web contents
106 // Along the chain, the original URL is passed and compared, to detect 131 // Along the chain, the original URL is passed and compared, to detect
107 // possible navigation and cancel snapshot in that case. 132 // possible navigation and cancel snapshot in that case.
108 void RecentTabHelper::StartSnapshot() { 133 void RecentTabHelper::StartSnapshot() {
109 // TODO(dimich): Implement automatic cleanup as per design doc, based on 134 // 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( 135 page_model_->GetOfflineIdsForClientId(
115 client_id(), 136 client_id(),
116 base::Bind(&RecentTabHelper::ContinueSnapshotWithIdsToPurge, 137 base::Bind(&RecentTabHelper::ContinueSnapshotWithIdsToPurge,
117 weak_ptr_factory_.GetWeakPtr())); 138 weak_ptr_factory_.GetWeakPtr()));
118 } 139 }
119 140
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( 141 void RecentTabHelper::ContinueSnapshotWithIdsToPurge(
124 const std::vector<int64_t>& page_ids) { 142 const std::vector<int64_t>& page_ids) {
125 143
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( 144 page_model_->DeletePagesByOfflineId(
155 pages_to_purge, base::Bind(&RecentTabHelper::ContinueSnapshotAfterPurge, 145 page_ids, base::Bind(&RecentTabHelper::ContinueSnapshotAfterPurge,
156 weak_ptr_factory_.GetWeakPtr())); 146 weak_ptr_factory_.GetWeakPtr()));
157 } 147 }
158 148
159 void RecentTabHelper::ContinueSnapshotAfterPurge( 149 void RecentTabHelper::ContinueSnapshotAfterPurge(
160 OfflinePageModel::DeletePageResult result) { 150 OfflinePageModel::DeletePageResult result) {
161 if (result != OfflinePageModel::DeletePageResult::SUCCESS) { 151 if (result != OfflinePageModel::DeletePageResult::SUCCESS) {
162 // If previous pages can't be deleted, don't add new ones. 152 // If previous pages can't be deleted, don't add new ones.
163 ReportSnapshotCompleted(); 153 ReportSnapshotCompleted();
164 return; 154 return;
165 } 155 }
166 156
167 if (!IsSamePage()) { 157 if (!IsSamePage()) {
168 ReportSnapshotCompleted(); 158 ReportSnapshotCompleted();
169 return; 159 return;
170 } 160 }
171 161
172 // Create either test Archiver or a regular one. 162 std::unique_ptr<OfflinePageArchiver> archiver(
173 std::unique_ptr<OfflinePageArchiver> archiver; 163 delegate_->CreatePageArchiver(web_contents()));
dewittj 2016/06/24 23:10:33 nit: move this right into the SavePage call.
Dmitry Titov 2016/06/24 23:58:01 Done.
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 164
180 page_model_->SavePage( 165 page_model_->SavePage(
181 snapshot_url_, client_id(), std::move(archiver), 166 snapshot_url_, client_id(), std::move(archiver),
182 base::Bind(&RecentTabHelper::SavePageCallback, 167 base::Bind(&RecentTabHelper::SavePageCallback,
183 weak_ptr_factory_.GetWeakPtr())); 168 weak_ptr_factory_.GetWeakPtr()));
184 } 169 }
185 170
186 void RecentTabHelper::SavePageCallback(OfflinePageModel::SavePageResult result, 171 void RecentTabHelper::SavePageCallback(OfflinePageModel::SavePageResult result,
187 int64_t offline_id) { 172 int64_t offline_id) {
188 ReportSnapshotCompleted(); 173 ReportSnapshotCompleted();
189 } 174 }
190 175
191 void RecentTabHelper::ReportSnapshotCompleted() { 176 void RecentTabHelper::ReportSnapshotCompleted() {
192 snapshot_controller_->PendingSnapshotCompleted(); 177 snapshot_controller_->PendingSnapshotCompleted();
193 } 178 }
194 179
195 bool RecentTabHelper::IsSamePage() const { 180 bool RecentTabHelper::IsSamePage() const {
196 return web_contents() && 181 return web_contents() &&
197 (web_contents()->GetLastCommittedURL() == snapshot_url_); 182 (web_contents()->GetLastCommittedURL() == snapshot_url_);
198 } 183 }
199 184
200 ClientId RecentTabHelper::client_id() const { 185 ClientId RecentTabHelper::client_id() const {
201 return ClientId(kLastNNamespace, ""); 186 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 } 187 }
213 188
214 } // namespace offline_pages 189 } // namespace offline_pages
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698