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

Side by Side Diff: components/offline_pages/offline_page_model_impl.cc

Issue 2489443002: Move all components/offline_pages/ files into component/offline_pages/core (Closed)
Patch Set: more rebase Created 4 years 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
(Empty)
1 // Copyright 2016 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.
4
5 #include "components/offline_pages/offline_page_model_impl.h"
6
7 #include <algorithm>
8 #include <limits>
9
10 #include "base/bind.h"
11 #include "base/files/file_util.h"
12 #include "base/location.h"
13 #include "base/logging.h"
14 #include "base/metrics/histogram_macros.h"
15 #include "base/rand_util.h"
16 #include "base/sequenced_task_runner.h"
17 #include "base/strings/string16.h"
18 #include "base/strings/string_number_conversions.h"
19 #include "base/threading/thread_task_runner_handle.h"
20 #include "base/time/clock.h"
21 #include "base/time/time.h"
22 #include "components/offline_pages/archive_manager.h"
23 #include "components/offline_pages/client_namespace_constants.h"
24 #include "components/offline_pages/client_policy_controller.h"
25 #include "components/offline_pages/offline_page_item.h"
26 #include "components/offline_pages/offline_page_model_query.h"
27 #include "components/offline_pages/offline_page_storage_manager.h"
28 #include "url/gurl.h"
29
30 using ArchiverResult = offline_pages::OfflinePageArchiver::ArchiverResult;
31 using ClearStorageCallback =
32 offline_pages::OfflinePageStorageManager::ClearStorageCallback;
33 using ClearStorageResult =
34 offline_pages::OfflinePageStorageManager::ClearStorageResult;
35
36 namespace offline_pages {
37
38 namespace {
39
40 // The delay used to schedule the first clear storage request for storage
41 // manager after the model is loaded.
42 const base::TimeDelta kStorageManagerStartingDelay =
43 base::TimeDelta::FromSeconds(20);
44
45 int64_t GenerateOfflineId() {
46 return base::RandGenerator(std::numeric_limits<int64_t>::max()) + 1;
47 }
48
49 // The maximum histogram size for the metrics that measure time between views of
50 // a given page.
51 const base::TimeDelta kMaxOpenedPageHistogramBucket =
52 base::TimeDelta::FromDays(90);
53
54 SavePageResult ToSavePageResult(ArchiverResult archiver_result) {
55 SavePageResult result;
56 switch (archiver_result) {
57 case ArchiverResult::SUCCESSFULLY_CREATED:
58 result = SavePageResult::SUCCESS;
59 break;
60 case ArchiverResult::ERROR_DEVICE_FULL:
61 result = SavePageResult::DEVICE_FULL;
62 break;
63 case ArchiverResult::ERROR_CONTENT_UNAVAILABLE:
64 result = SavePageResult::CONTENT_UNAVAILABLE;
65 break;
66 case ArchiverResult::ERROR_ARCHIVE_CREATION_FAILED:
67 result = SavePageResult::ARCHIVE_CREATION_FAILED;
68 break;
69 case ArchiverResult::ERROR_CANCELED:
70 result = SavePageResult::CANCELLED;
71 break;
72 case ArchiverResult::ERROR_SECURITY_CERTIFICATE:
73 result = SavePageResult::SECURITY_CERTIFICATE_ERROR;
74 break;
75 default:
76 NOTREACHED();
77 result = SavePageResult::CONTENT_UNAVAILABLE;
78 }
79 return result;
80 }
81
82 std::string AddHistogramSuffix(const ClientId& client_id,
83 const char* histogram_name) {
84 if (client_id.name_space.empty()) {
85 NOTREACHED();
86 return histogram_name;
87 }
88 std::string adjusted_histogram_name(histogram_name);
89 adjusted_histogram_name += ".";
90 adjusted_histogram_name += client_id.name_space;
91 return adjusted_histogram_name;
92 }
93
94 void ReportStorageHistogramsAfterSave(
95 const ArchiveManager::StorageStats& storage_stats) {
96 const int kMB = 1024 * 1024;
97 int free_disk_space_mb =
98 static_cast<int>(storage_stats.free_disk_space / kMB);
99 UMA_HISTOGRAM_CUSTOM_COUNTS("OfflinePages.SavePage.FreeSpaceMB",
100 free_disk_space_mb, 1, 500000, 50);
101
102 int total_page_size_mb =
103 static_cast<int>(storage_stats.total_archives_size / kMB);
104 UMA_HISTOGRAM_COUNTS_10000("OfflinePages.TotalPageSize", total_page_size_mb);
105 }
106
107 void ReportStorageHistogramsAfterDelete(
108 const ArchiveManager::StorageStats& storage_stats) {
109 const int kMB = 1024 * 1024;
110 int free_disk_space_mb =
111 static_cast<int>(storage_stats.free_disk_space / kMB);
112 UMA_HISTOGRAM_CUSTOM_COUNTS("OfflinePages.DeletePage.FreeSpaceMB",
113 free_disk_space_mb, 1, 500000, 50);
114
115 int total_page_size_mb =
116 static_cast<int>(storage_stats.total_archives_size / kMB);
117 UMA_HISTOGRAM_COUNTS_10000("OfflinePages.TotalPageSize", total_page_size_mb);
118
119 if (storage_stats.free_disk_space > 0) {
120 int percentage_of_free = static_cast<int>(
121 1.0 * storage_stats.total_archives_size /
122 (storage_stats.total_archives_size + storage_stats.free_disk_space) *
123 100);
124 UMA_HISTOGRAM_PERCENTAGE(
125 "OfflinePages.DeletePage.TotalPageSizeAsPercentageOfFreeSpace",
126 percentage_of_free);
127 }
128 }
129
130 void ReportSavePageResultHistogramAfterSave(const ClientId& client_id,
131 SavePageResult result) {
132 // The histogram below is an expansion of the UMA_HISTOGRAM_ENUMERATION
133 // macro adapted to allow for a dynamically suffixed histogram name.
134 // Note: The factory creates and owns the histogram.
135 base::HistogramBase* histogram = base::LinearHistogram::FactoryGet(
136 AddHistogramSuffix(client_id, "OfflinePages.SavePageResult"),
137 1,
138 static_cast<int>(SavePageResult::RESULT_COUNT),
139 static_cast<int>(SavePageResult::RESULT_COUNT) + 1,
140 base::HistogramBase::kUmaTargetedHistogramFlag);
141 histogram->Add(static_cast<int>(result));
142 }
143
144 // Goes through the list of offline pages, compiling the following two metrics:
145 // - a count of the pages with the same URL
146 // - The difference between the |created_before| time and the creation time of
147 // the page with the closest creation time before |created_before|.
148 // Returns true if there was a page that was saved before |created_before| with
149 // a matching URL.
150 bool GetMatchingURLCountAndMostRecentCreationTime(
151 const std::map<int64_t, OfflinePageItem>& offline_pages,
152 std::string name_space,
153 const GURL& url,
154 base::Time created_before,
155 int* matching_url_count,
156 base::TimeDelta* most_recent_creation_time) {
157 int count = 0;
158
159 // Create a time that is very old, so that any valid time will be newer than
160 // it.
161 base::Time latest_time;
162 bool matching_page = false;
163
164 for (auto& id_page_pair : offline_pages) {
165 if (id_page_pair.second.client_id.name_space == name_space &&
166 url == id_page_pair.second.url) {
167 count++;
168 base::Time page_creation_time = id_page_pair.second.creation_time;
169 if (page_creation_time < created_before &&
170 page_creation_time > latest_time) {
171 latest_time = page_creation_time;
172 matching_page = true;
173 }
174 }
175 }
176
177 if (matching_url_count != nullptr)
178 *matching_url_count = count;
179 if (most_recent_creation_time != nullptr && latest_time != base::Time())
180 *most_recent_creation_time = created_before - latest_time;
181
182 return matching_page;
183 }
184
185 void ReportPageHistogramAfterSave(
186 ClientPolicyController* policy_controller_,
187 const std::map<int64_t, OfflinePageItem>& offline_pages,
188 const OfflinePageItem& offline_page,
189 const base::Time& save_time) {
190 DCHECK(policy_controller_);
191 // The histogram below is an expansion of the UMA_HISTOGRAM_TIMES
192 // macro adapted to allow for a dynamically suffixed histogram name.
193 // Note: The factory creates and owns the histogram.
194 base::HistogramBase* histogram = base::Histogram::FactoryTimeGet(
195 AddHistogramSuffix(offline_page.client_id, "OfflinePages.SavePageTime"),
196 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromSeconds(10),
197 50, base::HistogramBase::kUmaTargetedHistogramFlag);
198 histogram->AddTime(save_time - offline_page.creation_time);
199
200 // The histogram below is an expansion of the UMA_HISTOGRAM_CUSTOM_COUNTS
201 // macro adapted to allow for a dynamically suffixed histogram name.
202 // Note: The factory creates and owns the histogram.
203 // Reported as Kb between 1Kb and 10Mb.
204 histogram = base::Histogram::FactoryGet(
205 AddHistogramSuffix(offline_page.client_id, "OfflinePages.PageSize"),
206 1, 10000, 50, base::HistogramBase::kUmaTargetedHistogramFlag);
207 histogram->Add(offline_page.file_size / 1024);
208
209 if (policy_controller_->IsSupportedByDownload(
210 offline_page.client_id.name_space)) {
211 int matching_url_count;
212 base::TimeDelta time_since_most_recent_duplicate;
213 if (GetMatchingURLCountAndMostRecentCreationTime(
214 offline_pages, offline_page.client_id.name_space, offline_page.url,
215 offline_page.creation_time, &matching_url_count,
216 &time_since_most_recent_duplicate)) {
217 // Using CUSTOM_COUNTS instead of time-oriented histogram to record
218 // samples in seconds rather than milliseconds.
219 UMA_HISTOGRAM_CUSTOM_COUNTS(
220 "OfflinePages.DownloadSavedPageTimeSinceDuplicateSaved",
221 time_since_most_recent_duplicate.InSeconds(),
222 base::TimeDelta::FromSeconds(1).InSeconds(),
223 base::TimeDelta::FromDays(7).InSeconds(), 50);
224 }
225 UMA_HISTOGRAM_CUSTOM_COUNTS("OfflinePages.DownloadSavedPageDuplicateCount",
226 matching_url_count, 1, 20, 10);
227 }
228 }
229
230 void ReportPageHistogramsAfterDelete(
231 const std::map<int64_t, OfflinePageItem>& offline_pages,
232 const std::vector<OfflinePageItem>& deleted_pages,
233 const base::Time& delete_time) {
234 const int max_minutes = base::TimeDelta::FromDays(365).InMinutes();
235 int64_t total_size = 0;
236
237 for (const auto& page : deleted_pages) {
238 total_size += page.file_size;
239 ClientId client_id = page.client_id;
240
241 if (client_id.name_space == kDownloadNamespace) {
242 int remaining_pages_with_url;
243 GetMatchingURLCountAndMostRecentCreationTime(
244 offline_pages, page.client_id.name_space, page.url, base::Time::Max(),
245 &remaining_pages_with_url, nullptr);
246 UMA_HISTOGRAM_CUSTOM_COUNTS(
247 "OfflinePages.DownloadDeletedPageDuplicateCount",
248 remaining_pages_with_url, 1, 20, 10);
249 }
250
251 // The histograms below are an expansion of the UMA_HISTOGRAM_CUSTOM_COUNTS
252 // macro adapted to allow for a dynamically suffixed histogram name.
253 // Note: The factory creates and owns the histogram.
254 base::HistogramBase* histogram = base::Histogram::FactoryGet(
255 AddHistogramSuffix(client_id, "OfflinePages.PageLifetime"),
256 1, max_minutes, 100, base::HistogramBase::kUmaTargetedHistogramFlag);
257 histogram->Add((delete_time - page.creation_time).InMinutes());
258
259 histogram = base::Histogram::FactoryGet(
260 AddHistogramSuffix(
261 client_id, "OfflinePages.DeletePage.TimeSinceLastOpen"),
262 1, max_minutes, 100, base::HistogramBase::kUmaTargetedHistogramFlag);
263 histogram->Add((delete_time - page.last_access_time).InMinutes());
264
265 histogram = base::Histogram::FactoryGet(
266 AddHistogramSuffix(
267 client_id, "OfflinePages.DeletePage.LastOpenToCreated"),
268 1, max_minutes, 100, base::HistogramBase::kUmaTargetedHistogramFlag);
269 histogram->Add((page.last_access_time - page.creation_time).InMinutes());
270
271 // Reported as Kb between 1Kb and 10Mb.
272 histogram = base::Histogram::FactoryGet(
273 AddHistogramSuffix(client_id, "OfflinePages.DeletePage.PageSize"),
274 1, 10000, 50, base::HistogramBase::kUmaTargetedHistogramFlag);
275 histogram->Add(page.file_size / 1024);
276
277 histogram = base::Histogram::FactoryGet(
278 AddHistogramSuffix(client_id, "OfflinePages.DeletePage.AccessCount"),
279 1, 1000000, 50, base::HistogramBase::kUmaTargetedHistogramFlag);
280 histogram->Add(page.access_count);
281 }
282
283 if (deleted_pages.size() > 1) {
284 UMA_HISTOGRAM_COUNTS("OfflinePages.BatchDelete.Count",
285 static_cast<int32_t>(deleted_pages.size()));
286 UMA_HISTOGRAM_MEMORY_KB(
287 "OfflinePages.BatchDelete.TotalPageSize", total_size / 1024);
288 }
289 }
290
291 void ReportPageHistogramsAfterAccess(const OfflinePageItem& offline_page_item,
292 const base::Time& access_time) {
293 // The histogram below is an expansion of the UMA_HISTOGRAM_CUSTOM_COUNTS
294 // macro adapted to allow for a dynamically suffixed histogram name.
295 // Note: The factory creates and owns the histogram.
296 base::HistogramBase* histogram = base::Histogram::FactoryGet(
297 AddHistogramSuffix(
298 offline_page_item.client_id,
299 offline_page_item.access_count == 0 ?
300 "OfflinePages.FirstOpenSinceCreated" :
301 "OfflinePages.OpenSinceLastOpen"),
302 1, kMaxOpenedPageHistogramBucket.InMinutes(), 50,
303 base::HistogramBase::kUmaTargetedHistogramFlag);
304 histogram->Add(
305 (access_time - offline_page_item.last_access_time).InMinutes());
306 }
307
308 } // namespace
309
310 // protected
311 OfflinePageModelImpl::OfflinePageModelImpl()
312 : OfflinePageModel(), is_loaded_(false), weak_ptr_factory_(this) {}
313
314 OfflinePageModelImpl::OfflinePageModelImpl(
315 std::unique_ptr<OfflinePageMetadataStore> store,
316 const base::FilePath& archives_dir,
317 const scoped_refptr<base::SequencedTaskRunner>& task_runner)
318 : store_(std::move(store)),
319 archives_dir_(archives_dir),
320 is_loaded_(false),
321 policy_controller_(new ClientPolicyController()),
322 archive_manager_(new ArchiveManager(archives_dir, task_runner)),
323 testing_clock_(nullptr),
324 weak_ptr_factory_(this) {
325 archive_manager_->EnsureArchivesDirCreated(
326 base::Bind(&OfflinePageModelImpl::OnEnsureArchivesDirCreatedDone,
327 weak_ptr_factory_.GetWeakPtr(), base::TimeTicks::Now()));
328 }
329
330 OfflinePageModelImpl::~OfflinePageModelImpl() {}
331
332 void OfflinePageModelImpl::AddObserver(Observer* observer) {
333 observers_.AddObserver(observer);
334 }
335
336 void OfflinePageModelImpl::RemoveObserver(Observer* observer) {
337 observers_.RemoveObserver(observer);
338 }
339
340 void OfflinePageModelImpl::SavePage(
341 const SavePageParams& save_page_params,
342 std::unique_ptr<OfflinePageArchiver> archiver,
343 const SavePageCallback& callback) {
344 DCHECK(is_loaded_);
345
346 // Skip saving the page that is not intended to be saved, like local file
347 // page.
348 if (!OfflinePageModel::CanSaveURL(save_page_params.url)) {
349 InformSavePageDone(callback, SavePageResult::SKIPPED,
350 save_page_params.client_id, kInvalidOfflineId);
351 return;
352 }
353
354 // The web contents is not available if archiver is not created and passed.
355 if (!archiver.get()) {
356 InformSavePageDone(callback, SavePageResult::CONTENT_UNAVAILABLE,
357 save_page_params.client_id, kInvalidOfflineId);
358 return;
359 }
360
361 // If we already have an offline id, use it. If not, generate one.
362 int64_t offline_id = save_page_params.proposed_offline_id;
363 if (offline_id == kInvalidOfflineId)
364 offline_id = GenerateOfflineId();
365
366 archiver->CreateArchive(
367 archives_dir_, offline_id,
368 base::Bind(&OfflinePageModelImpl::OnCreateArchiveDone,
369 weak_ptr_factory_.GetWeakPtr(), save_page_params, offline_id,
370 GetCurrentTime(), callback));
371 pending_archivers_.push_back(std::move(archiver));
372 }
373
374 void OfflinePageModelImpl::MarkPageAccessed(int64_t offline_id) {
375 RunWhenLoaded(base::Bind(&OfflinePageModelImpl::MarkPageAccessedWhenLoadDone,
376 weak_ptr_factory_.GetWeakPtr(), offline_id));
377 }
378
379 void OfflinePageModelImpl::MarkPageAccessedWhenLoadDone(int64_t offline_id) {
380 DCHECK(is_loaded_);
381
382 auto iter = offline_pages_.find(offline_id);
383 if (iter == offline_pages_.end() || iter->second.IsExpired())
384 return;
385
386 // Make a copy of the cached item and update it. The cached item should only
387 // be updated upon the successful store operation.
388 OfflinePageItem offline_page_item = iter->second;
389
390 ReportPageHistogramsAfterAccess(offline_page_item, GetCurrentTime());
391
392 offline_page_item.last_access_time = GetCurrentTime();
393 offline_page_item.access_count++;
394
395 std::vector<OfflinePageItem> items = { offline_page_item };
396 store_->UpdateOfflinePages(
397 items, base::Bind(&OfflinePageModelImpl::OnMarkPageAccesseDone,
398 weak_ptr_factory_.GetWeakPtr(), offline_page_item));
399 }
400
401 void OfflinePageModelImpl::DeletePagesByOfflineId(
402 const std::vector<int64_t>& offline_ids,
403 const DeletePageCallback& callback) {
404 RunWhenLoaded(base::Bind(&OfflinePageModelImpl::DoDeletePagesByOfflineId,
405 weak_ptr_factory_.GetWeakPtr(), offline_ids,
406 callback));
407 }
408
409 void OfflinePageModelImpl::DoDeletePagesByOfflineId(
410 const std::vector<int64_t>& offline_ids,
411 const DeletePageCallback& callback) {
412 DCHECK(is_loaded_);
413
414 std::vector<base::FilePath> paths_to_delete;
415 for (const auto& offline_id : offline_ids) {
416 auto iter = offline_pages_.find(offline_id);
417 if (iter != offline_pages_.end() && !iter->second.IsExpired()) {
418 paths_to_delete.push_back(iter->second.file_path);
419 }
420 }
421
422 // If there're no pages to delete, return early.
423 if (paths_to_delete.empty()) {
424 InformDeletePageDone(callback, DeletePageResult::SUCCESS);
425 return;
426 }
427
428 archive_manager_->DeleteMultipleArchives(
429 paths_to_delete,
430 base::Bind(&OfflinePageModelImpl::OnDeleteArchiveFilesDone,
431 weak_ptr_factory_.GetWeakPtr(), offline_ids, callback));
432 }
433
434 void OfflinePageModelImpl::DeletePagesByClientIds(
435 const std::vector<ClientId>& client_ids,
436 const DeletePageCallback& callback) {
437 OfflinePageModelQueryBuilder builder;
438 builder
439 .SetClientIds(OfflinePageModelQuery::Requirement::INCLUDE_MATCHING,
440 client_ids)
441 .AllowExpiredPages(true);
442 auto delete_pages = base::Bind(&OfflinePageModelImpl::DeletePages,
443 weak_ptr_factory_.GetWeakPtr(), callback);
444 RunWhenLoaded(base::Bind(&OfflinePageModelImpl::GetPagesMatchingQuery,
445 weak_ptr_factory_.GetWeakPtr(),
446 base::Passed(builder.Build(GetPolicyController())),
447 delete_pages));
448 }
449
450 void OfflinePageModelImpl::DeletePages(
451 const DeletePageCallback& callback,
452 const MultipleOfflinePageItemResult& pages) {
453 DCHECK(is_loaded_);
454
455 std::vector<int64_t> offline_ids;
456 for (auto& page : pages)
457 offline_ids.emplace_back(page.offline_id);
458
459 DoDeletePagesByOfflineId(offline_ids, callback);
460 }
461
462 void OfflinePageModelImpl::GetPagesByClientIds(
463 const std::vector<ClientId>& client_ids,
464 const MultipleOfflinePageItemCallback& callback) {
465 OfflinePageModelQueryBuilder builder;
466 builder.SetClientIds(OfflinePageModelQuery::Requirement::INCLUDE_MATCHING,
467 client_ids);
468 RunWhenLoaded(base::Bind(&OfflinePageModelImpl::GetPagesMatchingQuery,
469 weak_ptr_factory_.GetWeakPtr(),
470 base::Passed(builder.Build(GetPolicyController())),
471 callback));
472 }
473
474 void OfflinePageModelImpl::DeleteCachedPagesByURLPredicate(
475 const UrlPredicate& predicate,
476 const DeletePageCallback& callback) {
477 RunWhenLoaded(
478 base::Bind(&OfflinePageModelImpl::DoDeleteCachedPagesByURLPredicate,
479 weak_ptr_factory_.GetWeakPtr(), predicate, callback));
480 }
481
482 void OfflinePageModelImpl::DoDeleteCachedPagesByURLPredicate(
483 const UrlPredicate& predicate,
484 const DeletePageCallback& callback) {
485 DCHECK(is_loaded_);
486
487 std::vector<int64_t> offline_ids;
488 for (const auto& id_page_pair : offline_pages_) {
489 if (IsRemovedOnCacheReset(id_page_pair.second) &&
490 predicate.Run(id_page_pair.second.url)) {
491 offline_ids.push_back(id_page_pair.first);
492 }
493 }
494 DoDeletePagesByOfflineId(offline_ids, callback);
495 }
496
497 void OfflinePageModelImpl::CheckPagesExistOffline(
498 const std::set<GURL>& urls,
499 const CheckPagesExistOfflineCallback& callback) {
500 OfflinePageModelQueryBuilder builder;
501 builder
502 .SetUrls(OfflinePageModelQuery::Requirement::INCLUDE_MATCHING,
503 std::vector<GURL>(urls.begin(), urls.end()))
504 .RequireRestrictedToOriginalTab(
505 OfflinePageModelQueryBuilder::Requirement::EXCLUDE_MATCHING);
506 auto pages_to_urls = base::Bind(
507 [](const CheckPagesExistOfflineCallback& callback,
508 const MultipleOfflinePageItemResult& pages) {
509 CheckPagesExistOfflineResult result;
510 for (auto& page : pages)
511 result.insert(page.url);
512 callback.Run(result);
513 },
514 callback);
515 RunWhenLoaded(base::Bind(&OfflinePageModelImpl::GetPagesMatchingQuery,
516 weak_ptr_factory_.GetWeakPtr(),
517 base::Passed(builder.Build(GetPolicyController())),
518 pages_to_urls));
519 }
520
521 void OfflinePageModelImpl::GetPagesMatchingQuery(
522 std::unique_ptr<OfflinePageModelQuery> query,
523 const MultipleOfflinePageItemCallback& callback) {
524 DCHECK(query);
525
526 MultipleOfflinePageItemResult offline_pages_result;
527
528 for (const auto& id_page_pair : offline_pages_) {
529 if (query->Matches(id_page_pair.second))
530 offline_pages_result.emplace_back(id_page_pair.second);
531 }
532
533 callback.Run(offline_pages_result);
534 }
535
536 void OfflinePageModelImpl::GetAllPages(
537 const MultipleOfflinePageItemCallback& callback) {
538 OfflinePageModelQueryBuilder builder;
539 RunWhenLoaded(base::Bind(&OfflinePageModelImpl::GetPagesMatchingQuery,
540 weak_ptr_factory_.GetWeakPtr(),
541 base::Passed(builder.Build(GetPolicyController())),
542 callback));
543 }
544
545 void OfflinePageModelImpl::GetAllPagesWithExpired(
546 const MultipleOfflinePageItemCallback& callback) {
547 OfflinePageModelQueryBuilder builder;
548 builder.AllowExpiredPages(true);
549
550 RunWhenLoaded(base::Bind(&OfflinePageModelImpl::GetPagesMatchingQuery,
551 weak_ptr_factory_.GetWeakPtr(),
552 base::Passed(builder.Build(GetPolicyController())),
553 callback));
554 }
555
556 void OfflinePageModelImpl::GetOfflineIdsForClientId(
557 const ClientId& client_id,
558 const MultipleOfflineIdCallback& callback) {
559 RunWhenLoaded(
560 base::Bind(&OfflinePageModelImpl::GetOfflineIdsForClientIdWhenLoadDone,
561 weak_ptr_factory_.GetWeakPtr(), client_id, callback));
562 }
563
564 void OfflinePageModelImpl::GetOfflineIdsForClientIdWhenLoadDone(
565 const ClientId& client_id,
566 const MultipleOfflineIdCallback& callback) const {
567 callback.Run(MaybeGetOfflineIdsForClientId(client_id));
568 }
569
570 const std::vector<int64_t> OfflinePageModelImpl::MaybeGetOfflineIdsForClientId(
571 const ClientId& client_id) const {
572 DCHECK(is_loaded_);
573 std::vector<int64_t> results;
574
575 // We want only all pages, including those marked for deletion.
576 // TODO(fgorski): actually use an index rather than linear scan.
577 for (const auto& id_page_pair : offline_pages_) {
578 if (id_page_pair.second.client_id == client_id &&
579 !id_page_pair.second.IsExpired()) {
580 results.push_back(id_page_pair.second.offline_id);
581 }
582 }
583 return results;
584 }
585
586 void OfflinePageModelImpl::GetPageByOfflineId(
587 int64_t offline_id,
588 const SingleOfflinePageItemCallback& callback) {
589 std::vector<int64_t> query_ids;
590 query_ids.emplace_back(offline_id);
591
592 OfflinePageModelQueryBuilder builder;
593 builder.SetOfflinePageIds(
594 OfflinePageModelQuery::Requirement::INCLUDE_MATCHING, query_ids);
595
596 auto multiple_callback = base::Bind(
597 [](const SingleOfflinePageItemCallback& callback,
598 const MultipleOfflinePageItemResult& result) {
599 DCHECK_LE(result.size(), 1U);
600 if (result.empty()) {
601 callback.Run(nullptr);
602 } else {
603 callback.Run(&result[0]);
604 }
605 },
606 callback);
607
608 RunWhenLoaded(base::Bind(&OfflinePageModelImpl::GetPagesMatchingQuery,
609 weak_ptr_factory_.GetWeakPtr(),
610 base::Passed(builder.Build(GetPolicyController())),
611 multiple_callback));
612 }
613
614 void OfflinePageModelImpl::GetPagesByURL(
615 const GURL& url,
616 URLSearchMode url_search_mode,
617 const MultipleOfflinePageItemCallback& callback) {
618 RunWhenLoaded(
619 base::Bind(&OfflinePageModelImpl::GetPagesByURLWhenLoadDone,
620 weak_ptr_factory_.GetWeakPtr(), url,
621 url_search_mode, callback));
622 }
623
624 void OfflinePageModelImpl::GetPagesByURLWhenLoadDone(
625 const GURL& url,
626 URLSearchMode url_search_mode,
627 const MultipleOfflinePageItemCallback& callback) const {
628 std::vector<OfflinePageItem> result;
629
630 GURL::Replacements remove_params;
631 remove_params.ClearRef();
632
633 GURL url_without_fragment =
634 url.ReplaceComponents(remove_params);
635
636 for (const auto& id_page_pair : offline_pages_) {
637 if (id_page_pair.second.IsExpired())
638 continue;
639 // First, search by last committed URL with fragment stripped.
640 if (url_without_fragment ==
641 id_page_pair.second.url.ReplaceComponents(remove_params)) {
642 result.push_back(id_page_pair.second);
643 continue;
644 }
645 // Then, search by original request URL if |url_search_mode| wants it.
646 // Note that we want to do the exact match with fragment included. This is
647 // because original URL is used for redirect purpose and it is always safer
648 // to support the exact redirect.
649 if (url_search_mode == URLSearchMode::SEARCH_BY_ALL_URLS &&
650 url == id_page_pair.second.original_url) {
651 result.push_back(id_page_pair.second);
652 }
653 }
654
655 callback.Run(result);
656 }
657
658 void OfflinePageModelImpl::CheckMetadataConsistency() {
659 archive_manager_->GetAllArchives(
660 base::Bind(&OfflinePageModelImpl::CheckMetadataConsistencyForArchivePaths,
661 weak_ptr_factory_.GetWeakPtr()));
662 }
663
664 void OfflinePageModelImpl::ExpirePages(
665 const std::vector<int64_t>& offline_ids,
666 const base::Time& expiration_time,
667 const base::Callback<void(bool)>& callback) {
668 std::vector<base::FilePath> paths_to_delete;
669 std::vector<OfflinePageItem> items_to_update;
670 for (int64_t offline_id : offline_ids) {
671 auto iter = offline_pages_.find(offline_id);
672 if (iter == offline_pages_.end())
673 continue;
674
675 OfflinePageItem offline_page = iter->second;
676 paths_to_delete.push_back(offline_page.file_path);
677 offline_page.expiration_time = expiration_time;
678
679 items_to_update.push_back(offline_page);
680 }
681
682 store_->UpdateOfflinePages(
683 items_to_update,
684 base::Bind(&OfflinePageModelImpl::OnExpirePageDone,
685 weak_ptr_factory_.GetWeakPtr(), expiration_time));
686
687 if (paths_to_delete.empty()) {
688 callback.Run(true);
689 return;
690 }
691 archive_manager_->DeleteMultipleArchives(paths_to_delete, callback);
692 }
693
694 void OfflinePageModelImpl::OnExpirePageDone(
695 const base::Time& expiration_time,
696 std::unique_ptr<OfflinePagesUpdateResult> result) {
697 UMA_HISTOGRAM_BOOLEAN("OfflinePages.ExpirePage.StoreUpdateResult",
698 result->updated_items.size() > 0);
699 for (const auto& expired_page : result->updated_items) {
700 const auto& iter = offline_pages_.find(expired_page.offline_id);
701 if (iter == offline_pages_.end())
702 continue;
703
704 iter->second.expiration_time = expiration_time;
705 ClientId client_id = iter->second.client_id;
706 offline_event_logger_.RecordPageExpired(
707 std::to_string(expired_page.offline_id));
708 base::HistogramBase* histogram = base::Histogram::FactoryGet(
709 AddHistogramSuffix(client_id, "OfflinePages.ExpirePage.PageLifetime"),
710 1, base::TimeDelta::FromDays(30).InMinutes(), 50,
711 base::HistogramBase::kUmaTargetedHistogramFlag);
712 histogram->Add((expiration_time - iter->second.creation_time).InMinutes());
713 histogram = base::Histogram::FactoryGet(
714 AddHistogramSuffix(client_id,
715 "OfflinePages.ExpirePage.TimeSinceLastAccess"),
716 1, base::TimeDelta::FromDays(30).InMinutes(), 50,
717 base::HistogramBase::kUmaTargetedHistogramFlag);
718 histogram->Add(
719 (expiration_time - iter->second.last_access_time).InMinutes());
720 }
721 }
722
723 ClientPolicyController* OfflinePageModelImpl::GetPolicyController() {
724 return policy_controller_.get();
725 }
726
727 OfflinePageMetadataStore* OfflinePageModelImpl::GetStoreForTesting() {
728 return store_.get();
729 }
730
731 OfflinePageStorageManager* OfflinePageModelImpl::GetStorageManager() {
732 return storage_manager_.get();
733 }
734
735 bool OfflinePageModelImpl::is_loaded() const {
736 return is_loaded_;
737 }
738
739 OfflineEventLogger* OfflinePageModelImpl::GetLogger() {
740 return &offline_event_logger_;
741 }
742
743 void OfflinePageModelImpl::OnCreateArchiveDone(
744 const SavePageParams& save_page_params,
745 int64_t offline_id,
746 const base::Time& start_time,
747 const SavePageCallback& callback,
748 OfflinePageArchiver* archiver,
749 ArchiverResult archiver_result,
750 const GURL& url,
751 const base::FilePath& file_path,
752 const base::string16& title,
753 int64_t file_size) {
754 if (save_page_params.url != url) {
755 DVLOG(1) << "Saved URL does not match requested URL.";
756 // TODO(fgorski): We have created an archive for a wrong URL. It should be
757 // deleted from here, once archiver has the right functionality.
758 InformSavePageDone(callback, SavePageResult::ARCHIVE_CREATION_FAILED,
759 save_page_params.client_id, offline_id);
760 DeletePendingArchiver(archiver);
761 return;
762 }
763
764 if (archiver_result != ArchiverResult::SUCCESSFULLY_CREATED) {
765 SavePageResult result = ToSavePageResult(archiver_result);
766 InformSavePageDone(
767 callback, result, save_page_params.client_id, offline_id);
768 DeletePendingArchiver(archiver);
769 return;
770 }
771 OfflinePageItem offline_page_item(url, offline_id, save_page_params.client_id,
772 file_path, file_size, start_time);
773 offline_page_item.title = title;
774 offline_page_item.original_url = save_page_params.original_url;
775 store_->AddOfflinePage(offline_page_item,
776 base::Bind(&OfflinePageModelImpl::OnAddOfflinePageDone,
777 weak_ptr_factory_.GetWeakPtr(), archiver,
778 callback, offline_page_item));
779 }
780
781 void OfflinePageModelImpl::OnAddOfflinePageDone(
782 OfflinePageArchiver* archiver,
783 const SavePageCallback& callback,
784 const OfflinePageItem& offline_page,
785 ItemActionStatus status) {
786 SavePageResult result;
787 if (status == ItemActionStatus::SUCCESS) {
788 offline_pages_[offline_page.offline_id] = offline_page;
789 result = SavePageResult::SUCCESS;
790 ReportPageHistogramAfterSave(policy_controller_.get(), offline_pages_,
791 offline_page, GetCurrentTime());
792 offline_event_logger_.RecordPageSaved(
793 offline_page.client_id.name_space, offline_page.url.spec(),
794 std::to_string(offline_page.offline_id));
795 } else if (status == ItemActionStatus::ALREADY_EXISTS) {
796 result = SavePageResult::ALREADY_EXISTS;
797 } else {
798 result = SavePageResult::STORE_FAILURE;
799 }
800 InformSavePageDone(callback, result, offline_page.client_id,
801 offline_page.offline_id);
802 if (result == SavePageResult::SUCCESS) {
803 DeleteExistingPagesWithSameURL(offline_page);
804 } else {
805 PostClearStorageIfNeededTask(false /* delayed */);
806 }
807
808 DeletePendingArchiver(archiver);
809 for (Observer& observer : observers_)
810 observer.OfflinePageModelChanged(this);
811 }
812
813 void OfflinePageModelImpl::OnMarkPageAccesseDone(
814 const OfflinePageItem& offline_page_item,
815 std::unique_ptr<OfflinePagesUpdateResult> result) {
816 // Update the item in the cache only upon success.
817 if (result->updated_items.size() > 0)
818 offline_pages_[offline_page_item.offline_id] = offline_page_item;
819
820 // No need to fire OfflinePageModelChanged event since updating access info
821 // should not have any impact to the UI.
822 }
823
824 void OfflinePageModelImpl::OnEnsureArchivesDirCreatedDone(
825 const base::TimeTicks& start_time) {
826 UMA_HISTOGRAM_TIMES("OfflinePages.Model.ArchiveDirCreationTime",
827 base::TimeTicks::Now() - start_time);
828
829 const int kResetAttemptsLeft = 1;
830 store_->Initialize(base::Bind(&OfflinePageModelImpl::OnStoreInitialized,
831 weak_ptr_factory_.GetWeakPtr(), start_time,
832 kResetAttemptsLeft));
833 }
834
835 void OfflinePageModelImpl::OnStoreInitialized(const base::TimeTicks& start_time,
836 int reset_attempts_left,
837 bool success) {
838 if (success) {
839 DCHECK_EQ(store_->state(), StoreState::LOADED);
840 store_->GetOfflinePages(
841 base::Bind(&OfflinePageModelImpl::OnInitialGetOfflinePagesDone,
842 weak_ptr_factory_.GetWeakPtr(), start_time));
843 return;
844 }
845
846 DCHECK_EQ(store_->state(), StoreState::FAILED_LOADING);
847 // If there are no more reset attempts left, stop here.
848 if (reset_attempts_left == 0) {
849 FinalizeModelLoad();
850 return;
851 }
852
853 // Otherwise reduce the remaining attempts counter and reset store.
854 store_->Reset(base::Bind(&OfflinePageModelImpl::OnStoreResetDone,
855 weak_ptr_factory_.GetWeakPtr(), start_time,
856 reset_attempts_left - 1));
857 }
858
859 void OfflinePageModelImpl::OnStoreResetDone(const base::TimeTicks& start_time,
860 int reset_attempts_left,
861 bool success) {
862 if (success) {
863 DCHECK_EQ(store_->state(), StoreState::NOT_LOADED);
864 store_->Initialize(base::Bind(&OfflinePageModelImpl::OnStoreInitialized,
865 weak_ptr_factory_.GetWeakPtr(), start_time,
866 reset_attempts_left));
867 return;
868 }
869
870 DCHECK_EQ(store_->state(), StoreState::FAILED_RESET);
871 FinalizeModelLoad();
872 }
873
874 void OfflinePageModelImpl::OnInitialGetOfflinePagesDone(
875 const base::TimeTicks& start_time,
876 const std::vector<OfflinePageItem>& offline_pages) {
877 DCHECK(!is_loaded_);
878
879 UMA_HISTOGRAM_TIMES("OfflinePages.Model.ConstructionToLoadedEventTime",
880 base::TimeTicks::Now() - start_time);
881
882 CacheLoadedData(offline_pages);
883 FinalizeModelLoad();
884
885 // Ensure necessary cleanup operations are started.
886 CheckMetadataConsistency();
887 }
888
889 void OfflinePageModelImpl::FinalizeModelLoad() {
890 is_loaded_ = true;
891
892 // All actions below are meant to be taken regardless of successful load of
893 // the store.
894
895 // Inform observers the load is done.
896 for (Observer& observer : observers_)
897 observer.OfflinePageModelLoaded(this);
898
899 // Run all the delayed tasks.
900 for (const auto& delayed_task : delayed_tasks_)
901 delayed_task.Run();
902 delayed_tasks_.clear();
903
904 // Clear storage.
905 PostClearStorageIfNeededTask(true /* delayed */);
906 }
907
908 void OfflinePageModelImpl::InformSavePageDone(const SavePageCallback& callback,
909 SavePageResult result,
910 const ClientId& client_id,
911 int64_t offline_id) {
912 ReportSavePageResultHistogramAfterSave(client_id, result);
913 archive_manager_->GetStorageStats(
914 base::Bind(&ReportStorageHistogramsAfterSave));
915 callback.Run(result, offline_id);
916 }
917
918 void OfflinePageModelImpl::DeleteExistingPagesWithSameURL(
919 const OfflinePageItem& offline_page) {
920 // Remove existing pages generated by the same policy and with same url.
921 size_t pages_allowed =
922 policy_controller_->GetPolicy(offline_page.client_id.name_space)
923 .pages_allowed_per_url;
924 if (pages_allowed == kUnlimitedPages)
925 return;
926 GetPagesByURL(
927 offline_page.url,
928 URLSearchMode::SEARCH_BY_FINAL_URL_ONLY,
929 base::Bind(&OfflinePageModelImpl::OnPagesFoundWithSameURL,
930 weak_ptr_factory_.GetWeakPtr(), offline_page, pages_allowed));
931 }
932
933 void OfflinePageModelImpl::OnPagesFoundWithSameURL(
934 const OfflinePageItem& offline_page,
935 size_t pages_allowed,
936 const MultipleOfflinePageItemResult& items) {
937 std::vector<OfflinePageItem> pages_to_delete;
938 for (const auto& item : items) {
939 if (item.offline_id != offline_page.offline_id &&
940 item.client_id.name_space == offline_page.client_id.name_space) {
941 pages_to_delete.push_back(item);
942 }
943 }
944 // Only keep |pages_allowed|-1 of most fresh pages and delete others, by
945 // sorting pages with the oldest ones first and resize the vector.
946 if (pages_to_delete.size() >= pages_allowed) {
947 sort(pages_to_delete.begin(), pages_to_delete.end(),
948 [](const OfflinePageItem& a, const OfflinePageItem& b) -> bool {
949 return a.last_access_time < b.last_access_time;
950 });
951 pages_to_delete.resize(pages_to_delete.size() - pages_allowed + 1);
952 }
953 std::vector<int64_t> page_ids_to_delete;
954 for (const auto& item : pages_to_delete)
955 page_ids_to_delete.push_back(item.offline_id);
956 DeletePagesByOfflineId(
957 page_ids_to_delete,
958 base::Bind(&OfflinePageModelImpl::OnDeleteOldPagesWithSameURL,
959 weak_ptr_factory_.GetWeakPtr()));
960 }
961
962 void OfflinePageModelImpl::OnDeleteOldPagesWithSameURL(
963 DeletePageResult result) {
964 // TODO(romax) Add UMAs for failure cases.
965 PostClearStorageIfNeededTask(false /* delayed */);
966 }
967
968 void OfflinePageModelImpl::DeletePendingArchiver(
969 OfflinePageArchiver* archiver) {
970 pending_archivers_.erase(std::find(pending_archivers_.begin(),
971 pending_archivers_.end(), archiver));
972 }
973
974 void OfflinePageModelImpl::OnDeleteArchiveFilesDone(
975 const std::vector<int64_t>& offline_ids,
976 const DeletePageCallback& callback,
977 bool success) {
978 if (!success) {
979 InformDeletePageDone(callback, DeletePageResult::DEVICE_FAILURE);
980 return;
981 }
982
983 store_->RemoveOfflinePages(
984 offline_ids, base::Bind(&OfflinePageModelImpl::OnRemoveOfflinePagesDone,
985 weak_ptr_factory_.GetWeakPtr(), callback));
986 }
987
988 void OfflinePageModelImpl::OnRemoveOfflinePagesDone(
989 const DeletePageCallback& callback,
990 std::unique_ptr<OfflinePagesUpdateResult> result) {
991 ReportPageHistogramsAfterDelete(offline_pages_, result->updated_items,
992 GetCurrentTime());
993
994 // This part of the loop is explicitly broken out, as it should be gone in
995 // fully asynchronous code.
996 for (const auto& page : result->updated_items) {
997 int64_t offline_id = page.offline_id;
998 offline_event_logger_.RecordPageDeleted(std::to_string(offline_id));
999 auto iter = offline_pages_.find(offline_id);
1000 if (iter == offline_pages_.end())
1001 continue;
1002 offline_pages_.erase(iter);
1003 }
1004
1005 for (const auto& page : result->updated_items) {
1006 for (Observer& observer : observers_)
1007 observer.OfflinePageDeleted(page.offline_id, page.client_id);
1008 }
1009
1010 // TODO(fgorski): React the FAILED_INITIALIZATION, FAILED_RESET here.
1011 // TODO(fgorski): We need a better callback interface for the Remove action on
1012 // the this class. Currently removing an item that does not exist is
1013 // considered a success, but not called out as such to the caller.
1014 DeletePageResult delete_result;
1015 if (result->store_state == StoreState::LOADED)
1016 delete_result = DeletePageResult::SUCCESS;
1017 else
1018 delete_result = DeletePageResult::STORE_FAILURE;
1019
1020 InformDeletePageDone(callback, delete_result);
1021 }
1022
1023 void OfflinePageModelImpl::InformDeletePageDone(
1024 const DeletePageCallback& callback,
1025 DeletePageResult result) {
1026 UMA_HISTOGRAM_ENUMERATION("OfflinePages.DeletePageResult",
1027 static_cast<int>(result),
1028 static_cast<int>(DeletePageResult::RESULT_COUNT));
1029 archive_manager_->GetStorageStats(
1030 base::Bind(&ReportStorageHistogramsAfterDelete));
1031 if (!callback.is_null())
1032 callback.Run(result);
1033 }
1034
1035 void OfflinePageModelImpl::CheckMetadataConsistencyForArchivePaths(
1036 const std::set<base::FilePath>& archive_paths) {
1037 ExpirePagesMissingArchiveFile(archive_paths);
1038 DeleteOrphanedArchives(archive_paths);
1039 }
1040
1041 void OfflinePageModelImpl::ExpirePagesMissingArchiveFile(
1042 const std::set<base::FilePath>& archive_paths) {
1043 std::vector<int64_t> ids_of_pages_missing_archive_file;
1044 for (const auto& id_page_pair : offline_pages_) {
1045 if (archive_paths.count(id_page_pair.second.file_path) == 0UL)
1046 ids_of_pages_missing_archive_file.push_back(id_page_pair.first);
1047 }
1048
1049 if (ids_of_pages_missing_archive_file.empty())
1050 return;
1051
1052 ExpirePages(
1053 ids_of_pages_missing_archive_file, GetCurrentTime(),
1054 base::Bind(&OfflinePageModelImpl::OnExpirePagesMissingArchiveFileDone,
1055 weak_ptr_factory_.GetWeakPtr(),
1056 ids_of_pages_missing_archive_file));
1057 }
1058
1059 void OfflinePageModelImpl::OnExpirePagesMissingArchiveFileDone(
1060 const std::vector<int64_t>& offline_ids,
1061 bool success) {
1062 UMA_HISTOGRAM_COUNTS("OfflinePages.Consistency.PagesMissingArchiveFileCount",
1063 static_cast<int32_t>(offline_ids.size()));
1064 UMA_HISTOGRAM_BOOLEAN(
1065 "OfflinePages.Consistency.ExpirePagesMissingArchiveFileResult", success);
1066 }
1067
1068 void OfflinePageModelImpl::DeleteOrphanedArchives(
1069 const std::set<base::FilePath>& archive_paths) {
1070 // Archives are considered orphaned unless they are pointed to by some pages.
1071 std::set<base::FilePath> orphaned_archive_set(archive_paths);
1072 for (const auto& id_page_pair : offline_pages_)
1073 orphaned_archive_set.erase(id_page_pair.second.file_path);
1074
1075 if (orphaned_archive_set.empty())
1076 return;
1077
1078 std::vector<base::FilePath> orphaned_archives(orphaned_archive_set.begin(),
1079 orphaned_archive_set.end());
1080 archive_manager_->DeleteMultipleArchives(
1081 orphaned_archives,
1082 base::Bind(&OfflinePageModelImpl::OnDeleteOrphanedArchivesDone,
1083 weak_ptr_factory_.GetWeakPtr(), orphaned_archives));
1084 }
1085
1086 void OfflinePageModelImpl::OnDeleteOrphanedArchivesDone(
1087 const std::vector<base::FilePath>& archives,
1088 bool success) {
1089 UMA_HISTOGRAM_COUNTS("OfflinePages.Consistency.OrphanedArchivesCount",
1090 static_cast<int32_t>(archives.size()));
1091 UMA_HISTOGRAM_BOOLEAN("OfflinePages.Consistency.DeleteOrphanedArchivesResult",
1092 success);
1093 }
1094
1095 void OfflinePageModelImpl::CacheLoadedData(
1096 const std::vector<OfflinePageItem>& offline_pages) {
1097 offline_pages_.clear();
1098 for (const auto& offline_page : offline_pages)
1099 offline_pages_[offline_page.offline_id] = offline_page;
1100 }
1101
1102 void OfflinePageModelImpl::ClearStorageIfNeeded(
1103 const ClearStorageCallback& callback) {
1104 // Create Storage Manager if necessary.
1105 if (!storage_manager_) {
1106 storage_manager_.reset(new OfflinePageStorageManager(
1107 this, GetPolicyController(), archive_manager_.get()));
1108 }
1109 storage_manager_->ClearPagesIfNeeded(callback);
1110 }
1111
1112 void OfflinePageModelImpl::OnStorageCleared(size_t expired_page_count,
1113 ClearStorageResult result) {
1114 UMA_HISTOGRAM_ENUMERATION("OfflinePages.ClearStorageResult",
1115 static_cast<int>(result),
1116 static_cast<int>(ClearStorageResult::RESULT_COUNT));
1117 if (expired_page_count > 0) {
1118 UMA_HISTOGRAM_COUNTS("OfflinePages.ExpirePage.BatchSize",
1119 static_cast<int32_t>(expired_page_count));
1120 }
1121 }
1122
1123 void OfflinePageModelImpl::PostClearStorageIfNeededTask(bool delayed) {
1124 base::TimeDelta delay =
1125 delayed ? kStorageManagerStartingDelay : base::TimeDelta();
1126 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
1127 FROM_HERE, base::Bind(&OfflinePageModelImpl::ClearStorageIfNeeded,
1128 weak_ptr_factory_.GetWeakPtr(),
1129 base::Bind(&OfflinePageModelImpl::OnStorageCleared,
1130 weak_ptr_factory_.GetWeakPtr())),
1131 delay);
1132 }
1133
1134 bool OfflinePageModelImpl::IsRemovedOnCacheReset(
1135 const OfflinePageItem& offline_page) const {
1136 return policy_controller_->IsRemovedOnCacheReset(
1137 offline_page.client_id.name_space);
1138 }
1139
1140 void OfflinePageModelImpl::RunWhenLoaded(const base::Closure& task) {
1141 if (!is_loaded_) {
1142 delayed_tasks_.push_back(task);
1143 return;
1144 }
1145
1146 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, task);
1147 }
1148
1149 base::Time OfflinePageModelImpl::GetCurrentTime() const {
1150 return testing_clock_ ? testing_clock_->Now() : base::Time::Now();
1151 }
1152
1153 } // namespace offline_pages
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698