1 // Copyright (c) 2012 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 // The history system runs on a background thread so that potentially slow
6 // database operations don't delay the browser. This backend processing is
7 // represented by HistoryBackend. The HistoryService's job is to dispatch to
10 // Main thread History thread
11 // ----------- --------------
12 // HistoryService <----------------> HistoryBackend
14 // -> SQLite connection to History
15 // -> ThumbnailDatabase
16 // -> SQLite connection to Thumbnails
19 #include "chrome/browser/history/history_service.h"
21 #include "base/bind_helpers.h"
22 #include "base/callback.h"
23 #include "base/command_line.h"
24 #include "base/compiler_specific.h"
25 #include "base/location.h"
26 #include "base/memory/ref_counted.h"
27 #include "base/message_loop/message_loop.h"
28 #include "base/path_service.h"
29 #include "base/prefs/pref_service.h"
30 #include "base/thread_task_runner_handle.h"
31 #include "base/threading/thread.h"
32 #include "base/time/time.h"
33 #include "chrome/browser/browser_process.h"
34 #include "chrome/browser/chrome_notification_types.h"
35 #include "chrome/browser/history/download_row.h"
36 #include "chrome/browser/history/history_backend.h"
37 #include "chrome/browser/history/history_notifications.h"
38 #include "chrome/browser/history/in_memory_history_backend.h"
39 #include "chrome/browser/history/in_memory_url_index.h"
40 #include "chrome/browser/history/top_sites.h"
41 #include "chrome/browser/history/visit_database.h"
42 #include "chrome/browser/history/visit_filter.h"
43 #include "chrome/browser/history/web_history_service.h"
44 #include "chrome/browser/history/web_history_service_factory.h"
45 #include "chrome/browser/profiles/profile.h"
46 #include "chrome/common/chrome_constants.h"
47 #include "chrome/common/chrome_switches.h"
48 #include "chrome/common/importer/imported_favicon_usage.h"
49 #include "chrome/common/pref_names.h"
50 #include "chrome/common/url_constants.h"
51 #include "components/dom_distiller/core/url_constants.h"
52 #include "components/history/core/browser/history_client.h"
53 #include "components/history/core/browser/history_types.h"
54 #include "components/history/core/browser/in_memory_database.h"
55 #include "components/history/core/browser/keyword_search_term.h"
56 #include "components/history/core/common/thumbnail_score.h"
57 #include "components/visitedlink/browser/visitedlink_master.h"
58 #include "content/public/browser/browser_thread.h"
59 #include "content/public/browser/download_item.h"
60 #include "content/public/browser/notification_service.h"
61 #include "sync/api/sync_error_factory.h"
62 #include "third_party/skia/include/core/SkBitmap.h"
65 using history::HistoryBackend;
66 using history::KeywordID;
70 static const char* kHistoryThreadName = "Chrome_HistoryThread";
72 void RunWithFaviconResults(
73 const favicon_base::FaviconResultsCallback& callback,
74 std::vector<favicon_base::FaviconRawBitmapResult>* bitmap_results) {
75 callback.Run(*bitmap_results);
78 void RunWithFaviconResult(
79 const favicon_base::FaviconRawBitmapCallback& callback,
80 favicon_base::FaviconRawBitmapResult* bitmap_result) {
81 callback.Run(*bitmap_result);
84 void RunWithQueryURLResult(const HistoryService::QueryURLCallback& callback,
85 const history::QueryURLResult* result) {
86 callback.Run(result->success, result->row, result->visits);
89 void RunWithVisibleVisitCountToHostResult(
90 const HistoryService::GetVisibleVisitCountToHostCallback& callback,
91 const history::VisibleVisitCountToHostResult* result) {
92 callback.Run(result->success, result->count, result->first_visit);
95 // Extract history::URLRows into GURLs for VisitedLinkMaster.
96 class URLIteratorFromURLRows
97 : public visitedlink::VisitedLinkMaster::URLIterator {
99 explicit URLIteratorFromURLRows(const history::URLRows& url_rows)
100 : itr_(url_rows.begin()),
101 end_(url_rows.end()) {
104 virtual const GURL& NextURL() OVERRIDE {
105 return (itr_++)->url();
108 virtual bool HasNextURL() const OVERRIDE {
113 history::URLRows::const_iterator itr_;
114 history::URLRows::const_iterator end_;
116 DISALLOW_COPY_AND_ASSIGN(URLIteratorFromURLRows);
119 // Callback from WebHistoryService::ExpireWebHistory().
120 void ExpireWebHistoryComplete(bool success) {
121 // Ignore the result.
123 // TODO(davidben): ExpireLocalAndRemoteHistoryBetween callback should not fire
124 // until this completes.
129 // Sends messages from the backend to us on the main thread. This must be a
130 // separate class from the history service so that it can hold a reference to
131 // the history service (otherwise we would have to manually AddRef and
132 // Release when the Backend has a reference to us).
133 class HistoryService::BackendDelegate : public HistoryBackend::Delegate {
136 const base::WeakPtr<HistoryService>& history_service,
137 const scoped_refptr<base::SequencedTaskRunner>& service_task_runner,
139 : history_service_(history_service),
140 service_task_runner_(service_task_runner),
144 virtual void NotifyProfileError(sql::InitStatus init_status) OVERRIDE {
145 // Send to the history service on the main thread.
146 service_task_runner_->PostTask(
148 base::Bind(&HistoryService::NotifyProfileError, history_service_,
152 virtual void SetInMemoryBackend(
153 scoped_ptr<history::InMemoryHistoryBackend> backend) OVERRIDE {
154 // Send the backend to the history service on the main thread.
155 service_task_runner_->PostTask(
157 base::Bind(&HistoryService::SetInMemoryBackend, history_service_,
158 base::Passed(&backend)));
161 virtual void NotifyFaviconChanged(const std::set<GURL>& urls) OVERRIDE {
162 // Send the notification to the history service on the main thread.
163 service_task_runner_->PostTask(
166 &HistoryService::NotifyFaviconChanged, history_service_, urls));
169 virtual void BroadcastNotifications(
171 scoped_ptr<history::HistoryDetails> details) OVERRIDE {
172 // Send the notification on the history thread.
173 if (content::NotificationService::current()) {
174 content::Details<history::HistoryDetails> det(details.get());
175 content::NotificationService::current()->Notify(
176 type, content::Source<Profile>(profile_), det);
178 // Send the notification to the history service on the main thread.
179 service_task_runner_->PostTask(
181 base::Bind(&HistoryService::BroadcastNotificationsHelper,
182 history_service_, type, base::Passed(&details)));
185 virtual void DBLoaded() OVERRIDE {
186 service_task_runner_->PostTask(
188 base::Bind(&HistoryService::OnDBLoaded, history_service_));
191 virtual void NotifyVisitDBObserversOnAddVisit(
192 const history::BriefVisitInfo& info) OVERRIDE {
193 service_task_runner_->PostTask(
195 base::Bind(&HistoryService::NotifyVisitDBObserversOnAddVisit,
196 history_service_, info));
200 const base::WeakPtr<HistoryService> history_service_;
201 const scoped_refptr<base::SequencedTaskRunner> service_task_runner_;
202 Profile* const profile_;
205 // The history thread is intentionally not a BrowserThread because the
206 // sync integration unit tests depend on being able to create more than one
208 HistoryService::HistoryService()
209 : thread_(new base::Thread(kHistoryThreadName)),
210 history_client_(NULL),
212 backend_loaded_(false),
214 weak_ptr_factory_(this) {
217 HistoryService::HistoryService(history::HistoryClient* client, Profile* profile)
218 : thread_(new base::Thread(kHistoryThreadName)),
219 history_client_(client),
221 visitedlink_master_(new visitedlink::VisitedLinkMaster(
222 profile, this, true)),
223 backend_loaded_(false),
225 weak_ptr_factory_(this) {
227 registrar_.Add(this, chrome::NOTIFICATION_HISTORY_URLS_DELETED,
228 content::Source<Profile>(profile_));
231 HistoryService::~HistoryService() {
232 DCHECK(thread_checker_.CalledOnValidThread());
233 // Shutdown the backend. This does nothing if Cleanup was already invoked.
237 bool HistoryService::BackendLoaded() {
238 DCHECK(thread_checker_.CalledOnValidThread());
239 return backend_loaded_;
242 void HistoryService::ClearCachedDataForContextID(
243 history::ContextID context_id) {
244 DCHECK(thread_) << "History service being called after cleanup";
245 DCHECK(thread_checker_.CalledOnValidThread());
246 ScheduleAndForget(PRIORITY_NORMAL,
247 &HistoryBackend::ClearCachedDataForContextID, context_id);
250 history::URLDatabase* HistoryService::InMemoryDatabase() {
251 DCHECK(thread_checker_.CalledOnValidThread());
252 return in_memory_backend_ ? in_memory_backend_->db() : NULL;
255 bool HistoryService::GetTypedCountForURL(const GURL& url, int* typed_count) {
256 DCHECK(thread_checker_.CalledOnValidThread());
257 history::URLRow url_row;
258 if (!GetRowForURL(url, &url_row))
260 *typed_count = url_row.typed_count();
264 bool HistoryService::GetLastVisitTimeForURL(const GURL& url,
265 base::Time* last_visit) {
266 DCHECK(thread_checker_.CalledOnValidThread());
267 history::URLRow url_row;
268 if (!GetRowForURL(url, &url_row))
270 *last_visit = url_row.last_visit();
274 bool HistoryService::GetVisitCountForURL(const GURL& url, int* visit_count) {
275 DCHECK(thread_checker_.CalledOnValidThread());
276 history::URLRow url_row;
277 if (!GetRowForURL(url, &url_row))
279 *visit_count = url_row.visit_count();
283 history::TypedUrlSyncableService* HistoryService::GetTypedUrlSyncableService()
285 return history_backend_->GetTypedUrlSyncableService();
288 void HistoryService::Shutdown() {
289 DCHECK(thread_checker_.CalledOnValidThread());
293 void HistoryService::SetKeywordSearchTermsForURL(const GURL& url,
294 KeywordID keyword_id,
295 const base::string16& term) {
296 DCHECK(thread_) << "History service being called after cleanup";
297 DCHECK(thread_checker_.CalledOnValidThread());
298 ScheduleAndForget(PRIORITY_UI,
299 &HistoryBackend::SetKeywordSearchTermsForURL,
300 url, keyword_id, term);
303 void HistoryService::DeleteAllSearchTermsForKeyword(KeywordID keyword_id) {
304 DCHECK(thread_) << "History service being called after cleanup";
305 DCHECK(thread_checker_.CalledOnValidThread());
307 if (in_memory_backend_)
308 in_memory_backend_->DeleteAllSearchTermsForKeyword(keyword_id);
310 ScheduleAndForget(PRIORITY_UI,
311 &HistoryBackend::DeleteAllSearchTermsForKeyword,
315 void HistoryService::DeleteKeywordSearchTermForURL(const GURL& url) {
316 DCHECK(thread_) << "History service being called after cleanup";
317 DCHECK(thread_checker_.CalledOnValidThread());
318 ScheduleAndForget(PRIORITY_UI, &HistoryBackend::DeleteKeywordSearchTermForURL,
322 void HistoryService::DeleteMatchingURLsForKeyword(KeywordID keyword_id,
323 const base::string16& term) {
324 DCHECK(thread_) << "History service being called after cleanup";
325 DCHECK(thread_checker_.CalledOnValidThread());
326 ScheduleAndForget(PRIORITY_UI, &HistoryBackend::DeleteMatchingURLsForKeyword,
330 void HistoryService::URLsNoLongerBookmarked(const std::set<GURL>& urls) {
331 DCHECK(thread_) << "History service being called after cleanup";
332 DCHECK(thread_checker_.CalledOnValidThread());
333 ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::URLsNoLongerBookmarked,
337 void HistoryService::ScheduleDBTask(scoped_ptr<history::HistoryDBTask> task,
338 base::CancelableTaskTracker* tracker) {
339 DCHECK(thread_) << "History service being called after cleanup";
340 DCHECK(thread_checker_.CalledOnValidThread());
341 base::CancelableTaskTracker::IsCanceledCallback is_canceled;
342 tracker->NewTrackedTaskId(&is_canceled);
343 // Use base::ThreadTaskRunnerHandler::Get() to get a message loop proxy to
344 // the current message loop so that we can forward the call to the method
345 // HistoryDBTask::DoneRunOnMainThread in the correct thread.
346 thread_->message_loop_proxy()->PostTask(
348 base::Bind(&HistoryBackend::ProcessDBTask,
349 history_backend_.get(),
351 base::ThreadTaskRunnerHandle::Get(),
355 void HistoryService::FlushForTest(const base::Closure& flushed) {
356 thread_->message_loop_proxy()->PostTaskAndReply(
357 FROM_HERE, base::Bind(&base::DoNothing), flushed);
360 void HistoryService::SetOnBackendDestroyTask(const base::Closure& task) {
361 DCHECK(thread_) << "History service being called after cleanup";
362 DCHECK(thread_checker_.CalledOnValidThread());
363 ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::SetOnBackendDestroyTask,
364 base::MessageLoop::current(), task);
367 void HistoryService::AddPage(const GURL& url,
369 history::ContextID context_id,
371 const GURL& referrer,
372 const history::RedirectList& redirects,
373 ui::PageTransition transition,
374 history::VisitSource visit_source,
375 bool did_replace_entry) {
376 DCHECK(thread_checker_.CalledOnValidThread());
378 history::HistoryAddPageArgs(url, time, context_id, page_id, referrer,
379 redirects, transition, visit_source,
383 void HistoryService::AddPage(const GURL& url,
385 history::VisitSource visit_source) {
386 DCHECK(thread_checker_.CalledOnValidThread());
388 history::HistoryAddPageArgs(url, time, NULL, 0, GURL(),
389 history::RedirectList(),
390 ui::PAGE_TRANSITION_LINK,
391 visit_source, false));
394 void HistoryService::AddPage(const history::HistoryAddPageArgs& add_page_args) {
395 DCHECK(thread_) << "History service being called after cleanup";
396 DCHECK(thread_checker_.CalledOnValidThread());
398 // Filter out unwanted URLs. We don't add auto-subframe URLs. They are a
399 // large part of history (think iframes for ads) and we never display them in
400 // history UI. We will still add manual subframes, which are ones the user
401 // has clicked on to get.
402 if (!CanAddURL(add_page_args.url))
405 // Add link & all redirects to visited link list.
406 if (visitedlink_master_) {
407 visitedlink_master_->AddURL(add_page_args.url);
409 if (!add_page_args.redirects.empty()) {
410 // We should not be asked to add a page in the middle of a redirect chain.
411 DCHECK_EQ(add_page_args.url,
412 add_page_args.redirects[add_page_args.redirects.size() - 1]);
414 // We need the !redirects.empty() condition above since size_t is unsigned
415 // and will wrap around when we subtract one from a 0 size.
416 for (size_t i = 0; i < add_page_args.redirects.size() - 1; i++)
417 visitedlink_master_->AddURL(add_page_args.redirects[i]);
421 ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::AddPage, add_page_args);
424 void HistoryService::AddPageNoVisitForBookmark(const GURL& url,
425 const base::string16& title) {
426 DCHECK(thread_) << "History service being called after cleanup";
427 DCHECK(thread_checker_.CalledOnValidThread());
431 ScheduleAndForget(PRIORITY_NORMAL,
432 &HistoryBackend::AddPageNoVisitForBookmark, url, title);
435 void HistoryService::SetPageTitle(const GURL& url,
436 const base::string16& title) {
437 DCHECK(thread_) << "History service being called after cleanup";
438 DCHECK(thread_checker_.CalledOnValidThread());
439 ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::SetPageTitle, url, title);
442 void HistoryService::UpdateWithPageEndTime(history::ContextID context_id,
446 DCHECK(thread_) << "History service being called after cleanup";
447 DCHECK(thread_checker_.CalledOnValidThread());
448 ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::UpdateWithPageEndTime,
449 context_id, page_id, url, end_ts);
452 void HistoryService::AddPageWithDetails(const GURL& url,
453 const base::string16& title,
458 history::VisitSource visit_source) {
459 DCHECK(thread_) << "History service being called after cleanup";
460 DCHECK(thread_checker_.CalledOnValidThread());
461 // Filter out unwanted URLs.
465 // Add to the visited links system.
466 if (visitedlink_master_)
467 visitedlink_master_->AddURL(url);
469 history::URLRow row(url);
470 row.set_title(title);
471 row.set_visit_count(visit_count);
472 row.set_typed_count(typed_count);
473 row.set_last_visit(last_visit);
474 row.set_hidden(hidden);
476 history::URLRows rows;
479 ScheduleAndForget(PRIORITY_NORMAL,
480 &HistoryBackend::AddPagesWithDetails, rows, visit_source);
483 void HistoryService::AddPagesWithDetails(const history::URLRows& info,
484 history::VisitSource visit_source) {
485 DCHECK(thread_) << "History service being called after cleanup";
486 DCHECK(thread_checker_.CalledOnValidThread());
487 // Add to the visited links system.
488 if (visitedlink_master_) {
489 std::vector<GURL> urls;
490 urls.reserve(info.size());
491 for (history::URLRows::const_iterator i = info.begin(); i != info.end();
493 urls.push_back(i->url());
495 visitedlink_master_->AddURLs(urls);
498 ScheduleAndForget(PRIORITY_NORMAL,
499 &HistoryBackend::AddPagesWithDetails, info, visit_source);
502 base::CancelableTaskTracker::TaskId HistoryService::GetFavicons(
503 const std::vector<GURL>& icon_urls,
505 const std::vector<int>& desired_sizes,
506 const favicon_base::FaviconResultsCallback& callback,
507 base::CancelableTaskTracker* tracker) {
508 DCHECK(thread_) << "History service being called after cleanup";
509 DCHECK(thread_checker_.CalledOnValidThread());
510 std::vector<favicon_base::FaviconRawBitmapResult>* results =
511 new std::vector<favicon_base::FaviconRawBitmapResult>();
512 return tracker->PostTaskAndReply(
513 thread_->message_loop_proxy().get(),
515 base::Bind(&HistoryBackend::GetFavicons,
516 history_backend_.get(),
521 base::Bind(&RunWithFaviconResults, callback, base::Owned(results)));
524 base::CancelableTaskTracker::TaskId HistoryService::GetFaviconsForURL(
525 const GURL& page_url,
527 const std::vector<int>& desired_sizes,
528 const favicon_base::FaviconResultsCallback& callback,
529 base::CancelableTaskTracker* tracker) {
530 DCHECK(thread_) << "History service being called after cleanup";
531 DCHECK(thread_checker_.CalledOnValidThread());
532 std::vector<favicon_base::FaviconRawBitmapResult>* results =
533 new std::vector<favicon_base::FaviconRawBitmapResult>();
534 return tracker->PostTaskAndReply(
535 thread_->message_loop_proxy().get(),
537 base::Bind(&HistoryBackend::GetFaviconsForURL,
538 history_backend_.get(),
543 base::Bind(&RunWithFaviconResults, callback, base::Owned(results)));
546 base::CancelableTaskTracker::TaskId HistoryService::GetLargestFaviconForURL(
547 const GURL& page_url,
548 const std::vector<int>& icon_types,
549 int minimum_size_in_pixels,
550 const favicon_base::FaviconRawBitmapCallback& callback,
551 base::CancelableTaskTracker* tracker) {
552 DCHECK(thread_) << "History service being called after cleanup";
553 DCHECK(thread_checker_.CalledOnValidThread());
554 favicon_base::FaviconRawBitmapResult* result =
555 new favicon_base::FaviconRawBitmapResult();
556 return tracker->PostTaskAndReply(
557 thread_->message_loop_proxy().get(),
559 base::Bind(&HistoryBackend::GetLargestFaviconForURL,
560 history_backend_.get(),
563 minimum_size_in_pixels,
565 base::Bind(&RunWithFaviconResult, callback, base::Owned(result)));
568 base::CancelableTaskTracker::TaskId HistoryService::GetFaviconForID(
569 favicon_base::FaviconID favicon_id,
571 const favicon_base::FaviconResultsCallback& callback,
572 base::CancelableTaskTracker* tracker) {
573 DCHECK(thread_) << "History service being called after cleanup";
574 DCHECK(thread_checker_.CalledOnValidThread());
575 std::vector<favicon_base::FaviconRawBitmapResult>* results =
576 new std::vector<favicon_base::FaviconRawBitmapResult>();
577 return tracker->PostTaskAndReply(
578 thread_->message_loop_proxy().get(),
580 base::Bind(&HistoryBackend::GetFaviconForID,
581 history_backend_.get(),
585 base::Bind(&RunWithFaviconResults, callback, base::Owned(results)));
588 base::CancelableTaskTracker::TaskId
589 HistoryService::UpdateFaviconMappingsAndFetch(
590 const GURL& page_url,
591 const std::vector<GURL>& icon_urls,
593 const std::vector<int>& desired_sizes,
594 const favicon_base::FaviconResultsCallback& callback,
595 base::CancelableTaskTracker* tracker) {
596 DCHECK(thread_) << "History service being called after cleanup";
597 DCHECK(thread_checker_.CalledOnValidThread());
598 std::vector<favicon_base::FaviconRawBitmapResult>* results =
599 new std::vector<favicon_base::FaviconRawBitmapResult>();
600 return tracker->PostTaskAndReply(
601 thread_->message_loop_proxy().get(),
603 base::Bind(&HistoryBackend::UpdateFaviconMappingsAndFetch,
604 history_backend_.get(),
610 base::Bind(&RunWithFaviconResults, callback, base::Owned(results)));
613 void HistoryService::MergeFavicon(
614 const GURL& page_url,
615 const GURL& icon_url,
616 favicon_base::IconType icon_type,
617 scoped_refptr<base::RefCountedMemory> bitmap_data,
618 const gfx::Size& pixel_size) {
619 DCHECK(thread_) << "History service being called after cleanup";
620 DCHECK(thread_checker_.CalledOnValidThread());
621 if (!CanAddURL(page_url))
624 ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::MergeFavicon, page_url,
625 icon_url, icon_type, bitmap_data, pixel_size);
628 void HistoryService::SetFavicons(
629 const GURL& page_url,
630 favicon_base::IconType icon_type,
631 const GURL& icon_url,
632 const std::vector<SkBitmap>& bitmaps) {
633 DCHECK(thread_) << "History service being called after cleanup";
634 DCHECK(thread_checker_.CalledOnValidThread());
635 if (!CanAddURL(page_url))
638 ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::SetFavicons, page_url,
639 icon_type, icon_url, bitmaps);
642 void HistoryService::SetFaviconsOutOfDateForPage(const GURL& page_url) {
643 DCHECK(thread_) << "History service being called after cleanup";
644 DCHECK(thread_checker_.CalledOnValidThread());
645 ScheduleAndForget(PRIORITY_NORMAL,
646 &HistoryBackend::SetFaviconsOutOfDateForPage, page_url);
649 void HistoryService::CloneFavicons(const GURL& old_page_url,
650 const GURL& new_page_url) {
651 DCHECK(thread_) << "History service being called after cleanup";
652 DCHECK(thread_checker_.CalledOnValidThread());
653 ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::CloneFavicons,
654 old_page_url, new_page_url);
657 void HistoryService::SetImportedFavicons(
658 const std::vector<ImportedFaviconUsage>& favicon_usage) {
659 DCHECK(thread_) << "History service being called after cleanup";
660 DCHECK(thread_checker_.CalledOnValidThread());
661 ScheduleAndForget(PRIORITY_NORMAL,
662 &HistoryBackend::SetImportedFavicons, favicon_usage);
665 base::CancelableTaskTracker::TaskId HistoryService::QueryURL(
668 const QueryURLCallback& callback,
669 base::CancelableTaskTracker* tracker) {
670 DCHECK(thread_) << "History service being called after cleanup";
671 DCHECK(thread_checker_.CalledOnValidThread());
672 history::QueryURLResult* query_url_result = new history::QueryURLResult();
673 return tracker->PostTaskAndReply(
674 thread_->message_loop_proxy().get(),
676 base::Bind(&HistoryBackend::QueryURL,
677 history_backend_.get(),
680 base::Unretained(query_url_result)),
682 &RunWithQueryURLResult, callback, base::Owned(query_url_result)));
685 // Downloads -------------------------------------------------------------------
687 // Handle creation of a download by creating an entry in the history service's
688 // 'downloads' table.
689 void HistoryService::CreateDownload(
690 const history::DownloadRow& create_info,
691 const HistoryService::DownloadCreateCallback& callback) {
692 DCHECK(thread_) << "History service being called after cleanup";
693 DCHECK(thread_checker_.CalledOnValidThread());
694 PostTaskAndReplyWithResult(
695 thread_->message_loop_proxy().get(),
698 &HistoryBackend::CreateDownload, history_backend_.get(), create_info),
702 void HistoryService::GetNextDownloadId(
703 const content::DownloadIdCallback& callback) {
704 DCHECK(thread_) << "History service being called after cleanup";
705 DCHECK(thread_checker_.CalledOnValidThread());
706 PostTaskAndReplyWithResult(
707 thread_->message_loop_proxy().get(),
709 base::Bind(&HistoryBackend::GetNextDownloadId, history_backend_.get()),
713 // Handle queries for a list of all downloads in the history database's
714 // 'downloads' table.
715 void HistoryService::QueryDownloads(
716 const DownloadQueryCallback& callback) {
717 DCHECK(thread_) << "History service being called after cleanup";
718 DCHECK(thread_checker_.CalledOnValidThread());
719 std::vector<history::DownloadRow>* rows =
720 new std::vector<history::DownloadRow>();
721 scoped_ptr<std::vector<history::DownloadRow> > scoped_rows(rows);
722 // Beware! The first Bind() does not simply |scoped_rows.get()| because
723 // base::Passed(&scoped_rows) nullifies |scoped_rows|, and compilers do not
724 // guarantee that the first Bind's arguments are evaluated before the second
726 thread_->message_loop_proxy()->PostTaskAndReply(
728 base::Bind(&HistoryBackend::QueryDownloads, history_backend_.get(), rows),
729 base::Bind(callback, base::Passed(&scoped_rows)));
732 // Handle updates for a particular download. This is a 'fire and forget'
733 // operation, so we don't need to be called back.
734 void HistoryService::UpdateDownload(const history::DownloadRow& data) {
735 DCHECK(thread_) << "History service being called after cleanup";
736 DCHECK(thread_checker_.CalledOnValidThread());
737 ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::UpdateDownload, data);
740 void HistoryService::RemoveDownloads(const std::set<uint32>& ids) {
741 DCHECK(thread_) << "History service being called after cleanup";
742 DCHECK(thread_checker_.CalledOnValidThread());
743 ScheduleAndForget(PRIORITY_NORMAL,
744 &HistoryBackend::RemoveDownloads, ids);
747 base::CancelableTaskTracker::TaskId HistoryService::QueryHistory(
748 const base::string16& text_query,
749 const history::QueryOptions& options,
750 const QueryHistoryCallback& callback,
751 base::CancelableTaskTracker* tracker) {
752 DCHECK(thread_) << "History service being called after cleanup";
753 DCHECK(thread_checker_.CalledOnValidThread());
754 history::QueryResults* query_results = new history::QueryResults();
755 return tracker->PostTaskAndReply(
756 thread_->message_loop_proxy().get(),
758 base::Bind(&HistoryBackend::QueryHistory,
759 history_backend_.get(),
762 base::Unretained(query_results)),
763 base::Bind(callback, base::Owned(query_results)));
766 base::CancelableTaskTracker::TaskId HistoryService::QueryRedirectsFrom(
767 const GURL& from_url,
768 const QueryRedirectsCallback& callback,
769 base::CancelableTaskTracker* tracker) {
770 DCHECK(thread_) << "History service being called after cleanup";
771 DCHECK(thread_checker_.CalledOnValidThread());
772 history::RedirectList* result = new history::RedirectList();
773 return tracker->PostTaskAndReply(
774 thread_->message_loop_proxy().get(),
776 base::Bind(&HistoryBackend::QueryRedirectsFrom,
777 history_backend_.get(),
779 base::Unretained(result)),
780 base::Bind(callback, base::Owned(result)));
783 base::CancelableTaskTracker::TaskId HistoryService::QueryRedirectsTo(
785 const QueryRedirectsCallback& callback,
786 base::CancelableTaskTracker* tracker) {
787 DCHECK(thread_) << "History service being called after cleanup";
788 DCHECK(thread_checker_.CalledOnValidThread());
789 history::RedirectList* result = new history::RedirectList();
790 return tracker->PostTaskAndReply(thread_->message_loop_proxy().get(),
792 base::Bind(&HistoryBackend::QueryRedirectsTo,
793 history_backend_.get(),
795 base::Unretained(result)),
796 base::Bind(callback, base::Owned(result)));
799 base::CancelableTaskTracker::TaskId HistoryService::GetVisibleVisitCountToHost(
801 const GetVisibleVisitCountToHostCallback& callback,
802 base::CancelableTaskTracker* tracker) {
803 DCHECK(thread_) << "History service being called after cleanup";
804 DCHECK(thread_checker_.CalledOnValidThread());
805 history::VisibleVisitCountToHostResult* result =
806 new history::VisibleVisitCountToHostResult();
807 return tracker->PostTaskAndReply(
808 thread_->message_loop_proxy().get(),
810 base::Bind(&HistoryBackend::GetVisibleVisitCountToHost,
811 history_backend_.get(),
813 base::Unretained(result)),
814 base::Bind(&RunWithVisibleVisitCountToHostResult,
816 base::Owned(result)));
819 base::CancelableTaskTracker::TaskId HistoryService::QueryMostVisitedURLs(
822 const QueryMostVisitedURLsCallback& callback,
823 base::CancelableTaskTracker* tracker) {
824 DCHECK(thread_) << "History service being called after cleanup";
825 DCHECK(thread_checker_.CalledOnValidThread());
826 history::MostVisitedURLList* result = new history::MostVisitedURLList();
827 return tracker->PostTaskAndReply(
828 thread_->message_loop_proxy().get(),
830 base::Bind(&HistoryBackend::QueryMostVisitedURLs,
831 history_backend_.get(),
834 base::Unretained(result)),
835 base::Bind(callback, base::Owned(result)));
838 base::CancelableTaskTracker::TaskId HistoryService::QueryFilteredURLs(
840 const history::VisitFilter& filter,
842 const QueryFilteredURLsCallback& callback,
843 base::CancelableTaskTracker* tracker) {
844 DCHECK(thread_) << "History service being called after cleanup";
845 DCHECK(thread_checker_.CalledOnValidThread());
846 history::FilteredURLList* result = new history::FilteredURLList();
847 return tracker->PostTaskAndReply(
848 thread_->message_loop_proxy().get(),
850 base::Bind(&HistoryBackend::QueryFilteredURLs,
851 history_backend_.get(),
855 base::Unretained(result)),
856 base::Bind(callback, base::Owned(result)));
859 void HistoryService::Cleanup() {
860 DCHECK(thread_checker_.CalledOnValidThread());
862 // We've already cleaned up.
866 weak_ptr_factory_.InvalidateWeakPtrs();
868 // Unload the backend.
869 if (history_backend_.get()) {
870 // Get rid of the in-memory backend.
871 in_memory_backend_.reset();
873 // Give the InMemoryURLIndex a chance to shutdown.
874 // NOTE: In tests, there may be no index.
875 if (in_memory_url_index_)
876 in_memory_url_index_->ShutDown();
878 // The backend's destructor must run on the history thread since it is not
879 // threadsafe. So this thread must not be the last thread holding a
880 // reference to the backend, or a crash could happen.
882 // We have a reference to the history backend. There is also an extra
883 // reference held by our delegate installed in the backend, which
884 // HistoryBackend::Closing will release. This means if we scheduled a call
885 // to HistoryBackend::Closing and *then* released our backend reference,
886 // there will be a race between us and the backend's Closing function to see
887 // who is the last holder of a reference. If the backend thread's Closing
888 // manages to run before we release our backend refptr, the last reference
889 // will be held by this thread and the destructor will be called from here.
891 // Therefore, we create a closure to run the Closing operation first. This
892 // holds a reference to the backend. Then we release our reference, then we
893 // schedule the task to run. After the task runs, it will delete its
894 // reference from the history thread, ensuring everything works properly.
896 // TODO(ajwong): Cleanup HistoryBackend lifetime issues.
897 // See http://crbug.com/99767.
898 history_backend_->AddRef();
899 base::Closure closing_task =
900 base::Bind(&HistoryBackend::Closing, history_backend_.get());
901 ScheduleTask(PRIORITY_NORMAL, closing_task);
902 closing_task.Reset();
903 HistoryBackend* raw_ptr = history_backend_.get();
904 history_backend_ = NULL;
905 thread_->message_loop()->ReleaseSoon(FROM_HERE, raw_ptr);
908 // Delete the thread, which joins with the background thread. We defensively
909 // NULL the pointer before deleting it in case somebody tries to use it
910 // during shutdown, but this shouldn't happen.
911 base::Thread* thread = thread_;
916 void HistoryService::Observe(int type,
917 const content::NotificationSource& source,
918 const content::NotificationDetails& details) {
919 DCHECK(thread_checker_.CalledOnValidThread());
924 case chrome::NOTIFICATION_HISTORY_URLS_DELETED: {
925 // Update the visited link system for deleted URLs. We will update the
926 // visited link system for added URLs as soon as we get the add
927 // notification (we don't have to wait for the backend, which allows us to
928 // be faster to update the state).
930 // For deleted URLs, we don't typically know what will be deleted since
931 // delete notifications are by time. We would also like to be more
932 // respectful of privacy and never tell the user something is gone when it
933 // isn't. Therefore, we update the delete URLs after the fact.
934 if (visitedlink_master_) {
935 content::Details<history::URLsDeletedDetails> deleted_details(details);
937 if (deleted_details->all_history) {
938 visitedlink_master_->DeleteAllURLs();
940 URLIteratorFromURLRows iterator(deleted_details->rows);
941 visitedlink_master_->DeleteURLs(&iterator);
952 void HistoryService::RebuildTable(
953 const scoped_refptr<URLEnumerator>& enumerator) {
954 DCHECK(thread_) << "History service being called after cleanup";
955 DCHECK(thread_checker_.CalledOnValidThread());
956 ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::IterateURLs, enumerator);
959 bool HistoryService::Init(const base::FilePath& history_dir, bool no_db) {
960 DCHECK(thread_) << "History service being called after cleanup";
961 DCHECK(thread_checker_.CalledOnValidThread());
962 base::Thread::Options options;
963 options.timer_slack = base::TIMER_SLACK_MAXIMUM;
964 if (!thread_->StartWithOptions(options)) {
969 history_dir_ = history_dir;
973 std::string languages =
974 profile_->GetPrefs()->GetString(prefs::kAcceptLanguages);
975 in_memory_url_index_.reset(new history::InMemoryURLIndex(
976 profile_, history_dir_, languages, history_client_));
977 in_memory_url_index_->Init();
980 // Create the history backend.
981 scoped_refptr<HistoryBackend> backend(
982 new HistoryBackend(history_dir_,
984 weak_ptr_factory_.GetWeakPtr(),
985 base::ThreadTaskRunnerHandle::Get(),
988 history_backend_.swap(backend);
990 // There may not be a profile when unit testing.
991 std::string languages;
993 PrefService* prefs = profile_->GetPrefs();
994 languages = prefs->GetString(prefs::kAcceptLanguages);
996 ScheduleAndForget(PRIORITY_UI, &HistoryBackend::Init, languages, no_db_);
998 if (visitedlink_master_) {
999 bool result = visitedlink_master_->Init();
1006 void HistoryService::ScheduleAutocomplete(const base::Callback<
1007 void(history::HistoryBackend*, history::URLDatabase*)>& callback) {
1008 DCHECK(thread_checker_.CalledOnValidThread());
1010 PRIORITY_UI, &HistoryBackend::ScheduleAutocomplete, callback);
1013 void HistoryService::ScheduleTask(SchedulePriority priority,
1014 const base::Closure& task) {
1015 DCHECK(thread_checker_.CalledOnValidThread());
1017 CHECK(thread_->message_loop());
1018 // TODO(brettw): Do prioritization.
1019 thread_->message_loop()->PostTask(FROM_HERE, task);
1023 bool HistoryService::CanAddURL(const GURL& url) {
1024 if (!url.is_valid())
1027 // TODO: We should allow kChromeUIScheme URLs if they have been explicitly
1028 // typed. Right now, however, these are marked as typed even when triggered
1029 // by a shortcut or menu action.
1030 if (url.SchemeIs(url::kJavaScriptScheme) ||
1031 url.SchemeIs(content::kChromeDevToolsScheme) ||
1032 url.SchemeIs(content::kChromeUIScheme) ||
1033 url.SchemeIs(content::kViewSourceScheme) ||
1034 url.SchemeIs(chrome::kChromeNativeScheme) ||
1035 url.SchemeIs(chrome::kChromeSearchScheme) ||
1036 url.SchemeIs(dom_distiller::kDomDistillerScheme))
1039 // Allow all about: and chrome: URLs except about:blank, since the user may
1040 // like to see "chrome://memory/", etc. in their history and autocomplete.
1041 if (url == GURL(url::kAboutBlankURL))
1047 base::WeakPtr<HistoryService> HistoryService::AsWeakPtr() {
1048 DCHECK(thread_checker_.CalledOnValidThread());
1049 return weak_ptr_factory_.GetWeakPtr();
1052 syncer::SyncMergeResult HistoryService::MergeDataAndStartSyncing(
1053 syncer::ModelType type,
1054 const syncer::SyncDataList& initial_sync_data,
1055 scoped_ptr<syncer::SyncChangeProcessor> sync_processor,
1056 scoped_ptr<syncer::SyncErrorFactory> error_handler) {
1057 DCHECK(thread_checker_.CalledOnValidThread());
1058 DCHECK_EQ(type, syncer::HISTORY_DELETE_DIRECTIVES);
1059 delete_directive_handler_.Start(this, initial_sync_data,
1060 sync_processor.Pass());
1061 return syncer::SyncMergeResult(type);
1064 void HistoryService::StopSyncing(syncer::ModelType type) {
1065 DCHECK(thread_checker_.CalledOnValidThread());
1066 DCHECK_EQ(type, syncer::HISTORY_DELETE_DIRECTIVES);
1067 delete_directive_handler_.Stop();
1070 syncer::SyncDataList HistoryService::GetAllSyncData(
1071 syncer::ModelType type) const {
1072 DCHECK(thread_checker_.CalledOnValidThread());
1073 DCHECK_EQ(type, syncer::HISTORY_DELETE_DIRECTIVES);
1074 // TODO(akalin): Keep track of existing delete directives.
1075 return syncer::SyncDataList();
1078 syncer::SyncError HistoryService::ProcessSyncChanges(
1079 const tracked_objects::Location& from_here,
1080 const syncer::SyncChangeList& change_list) {
1081 delete_directive_handler_.ProcessSyncChanges(this, change_list);
1082 return syncer::SyncError();
1085 syncer::SyncError HistoryService::ProcessLocalDeleteDirective(
1086 const sync_pb::HistoryDeleteDirectiveSpecifics& delete_directive) {
1087 DCHECK(thread_checker_.CalledOnValidThread());
1088 return delete_directive_handler_.ProcessLocalDeleteDirective(
1092 void HistoryService::SetInMemoryBackend(
1093 scoped_ptr<history::InMemoryHistoryBackend> mem_backend) {
1094 DCHECK(thread_checker_.CalledOnValidThread());
1095 DCHECK(!in_memory_backend_) << "Setting mem DB twice";
1096 in_memory_backend_.reset(mem_backend.release());
1098 // The database requires additional initialization once we own it.
1099 in_memory_backend_->AttachToHistoryService(profile_);
1102 void HistoryService::NotifyProfileError(sql::InitStatus init_status) {
1103 DCHECK(thread_checker_.CalledOnValidThread());
1104 if (history_client_)
1105 history_client_->NotifyProfileError(init_status);
1108 void HistoryService::DeleteURL(const GURL& url) {
1109 DCHECK(thread_) << "History service being called after cleanup";
1110 DCHECK(thread_checker_.CalledOnValidThread());
1111 // We will update the visited links when we observe the delete notifications.
1112 ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::DeleteURL, url);
1115 void HistoryService::DeleteURLsForTest(const std::vector<GURL>& urls) {
1116 DCHECK(thread_) << "History service being called after cleanup";
1117 DCHECK(thread_checker_.CalledOnValidThread());
1118 // We will update the visited links when we observe the delete
1120 ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::DeleteURLs, urls);
1123 void HistoryService::ExpireHistoryBetween(
1124 const std::set<GURL>& restrict_urls,
1127 const base::Closure& callback,
1128 base::CancelableTaskTracker* tracker) {
1129 DCHECK(thread_) << "History service being called after cleanup";
1130 DCHECK(thread_checker_.CalledOnValidThread());
1131 tracker->PostTaskAndReply(thread_->message_loop_proxy().get(),
1133 base::Bind(&HistoryBackend::ExpireHistoryBetween,
1141 void HistoryService::ExpireHistory(
1142 const std::vector<history::ExpireHistoryArgs>& expire_list,
1143 const base::Closure& callback,
1144 base::CancelableTaskTracker* tracker) {
1145 DCHECK(thread_) << "History service being called after cleanup";
1146 DCHECK(thread_checker_.CalledOnValidThread());
1147 tracker->PostTaskAndReply(
1148 thread_->message_loop_proxy().get(),
1150 base::Bind(&HistoryBackend::ExpireHistory, history_backend_, expire_list),
1154 void HistoryService::ExpireLocalAndRemoteHistoryBetween(
1155 const std::set<GURL>& restrict_urls,
1158 const base::Closure& callback,
1159 base::CancelableTaskTracker* tracker) {
1160 // TODO(dubroy): This should be factored out into a separate class that
1161 // dispatches deletions to the proper places.
1163 history::WebHistoryService* web_history =
1164 WebHistoryServiceFactory::GetForProfile(profile_);
1166 // TODO(dubroy): This API does not yet support deletion of specific URLs.
1167 DCHECK(restrict_urls.empty());
1169 delete_directive_handler_.CreateDeleteDirectives(
1170 std::set<int64>(), begin_time, end_time);
1172 // Attempt online deletion from the history server, but ignore the result.
1173 // Deletion directives ensure that the results will eventually be deleted.
1175 // TODO(davidben): |callback| should not run until this operation completes
1177 web_history->ExpireHistoryBetween(
1178 restrict_urls, begin_time, end_time,
1179 base::Bind(&ExpireWebHistoryComplete));
1181 ExpireHistoryBetween(restrict_urls, begin_time, end_time, callback, tracker);
1184 void HistoryService::BroadcastNotificationsHelper(
1186 scoped_ptr<history::HistoryDetails> details) {
1187 DCHECK(thread_checker_.CalledOnValidThread());
1188 // TODO(evanm): this is currently necessitated by generate_profile, which
1189 // runs without a browser process. generate_profile should really create
1190 // a browser process, at which point this check can then be nuked.
1191 if (!g_browser_process)
1197 // The source of all of our notifications is the profile. Note that this
1198 // pointer is NULL in unit tests.
1199 content::Source<Profile> source(profile_);
1201 // The details object just contains the pointer to the object that the
1202 // backend has allocated for us. The receiver of the notification will cast
1203 // this to the proper type.
1204 content::Details<history::HistoryDetails> det(details.get());
1206 content::NotificationService::current()->Notify(type, source, det);
1209 void HistoryService::OnDBLoaded() {
1210 DCHECK(thread_checker_.CalledOnValidThread());
1211 backend_loaded_ = true;
1212 content::NotificationService::current()->Notify(
1213 chrome::NOTIFICATION_HISTORY_LOADED,
1214 content::Source<Profile>(profile_),
1215 content::Details<HistoryService>(this));
1218 bool HistoryService::GetRowForURL(const GURL& url, history::URLRow* url_row) {
1219 DCHECK(thread_checker_.CalledOnValidThread());
1220 history::URLDatabase* db = InMemoryDatabase();
1221 return db && (db->GetRowForURL(url, url_row) != 0);
1224 void HistoryService::AddVisitDatabaseObserver(
1225 history::VisitDatabaseObserver* observer) {
1226 DCHECK(thread_checker_.CalledOnValidThread());
1227 visit_database_observers_.AddObserver(observer);
1230 void HistoryService::RemoveVisitDatabaseObserver(
1231 history::VisitDatabaseObserver* observer) {
1232 DCHECK(thread_checker_.CalledOnValidThread());
1233 visit_database_observers_.RemoveObserver(observer);
1236 void HistoryService::NotifyVisitDBObserversOnAddVisit(
1237 const history::BriefVisitInfo& info) {
1238 DCHECK(thread_checker_.CalledOnValidThread());
1239 FOR_EACH_OBSERVER(history::VisitDatabaseObserver, visit_database_observers_,
1243 scoped_ptr<base::CallbackList<void(const std::set<GURL>&)>::Subscription>
1244 HistoryService::AddFaviconChangedCallback(
1245 const HistoryService::OnFaviconChangedCallback& callback) {
1246 DCHECK(thread_checker_.CalledOnValidThread());
1247 return favicon_changed_callback_list_.Add(callback);
1250 void HistoryService::NotifyFaviconChanged(
1251 const std::set<GURL>& changed_favicons) {
1252 DCHECK(thread_checker_.CalledOnValidThread());
1253 favicon_changed_callback_list_.Notify(changed_favicons);