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/prefs/pref_service.h"
29 #include "base/thread_task_runner_handle.h"
30 #include "base/threading/thread.h"
31 #include "base/time/time.h"
32 #include "chrome/browser/browser_process.h"
33 #include "chrome/browser/chrome_notification_types.h"
34 #include "chrome/browser/history/download_row.h"
35 #include "chrome/browser/history/history_backend.h"
36 #include "chrome/browser/history/history_notifications.h"
37 #include "chrome/browser/history/in_memory_history_backend.h"
38 #include "chrome/browser/history/in_memory_url_index.h"
39 #include "chrome/browser/history/top_sites.h"
40 #include "chrome/browser/history/visit_database.h"
41 #include "chrome/browser/history/visit_filter.h"
42 #include "chrome/browser/history/web_history_service.h"
43 #include "chrome/browser/history/web_history_service_factory.h"
44 #include "chrome/browser/profiles/profile.h"
45 #include "chrome/common/chrome_constants.h"
46 #include "chrome/common/chrome_switches.h"
47 #include "chrome/common/importer/imported_favicon_usage.h"
48 #include "chrome/common/pref_names.h"
49 #include "chrome/common/url_constants.h"
50 #include "components/dom_distiller/core/url_constants.h"
51 #include "components/history/core/browser/history_client.h"
52 #include "components/history/core/browser/history_service_observer.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 const GURL& NextURL() override { return (itr_++)->url(); }
106 bool HasNextURL() const override { return itr_ != end_; }
109 history::URLRows::const_iterator itr_;
110 history::URLRows::const_iterator end_;
112 DISALLOW_COPY_AND_ASSIGN(URLIteratorFromURLRows);
115 // Callback from WebHistoryService::ExpireWebHistory().
116 void ExpireWebHistoryComplete(bool success) {
117 // Ignore the result.
119 // TODO(davidben): ExpireLocalAndRemoteHistoryBetween callback should not fire
120 // until this completes.
125 // Sends messages from the backend to us on the main thread. This must be a
126 // separate class from the history service so that it can hold a reference to
127 // the history service (otherwise we would have to manually AddRef and
128 // Release when the Backend has a reference to us).
129 class HistoryService::BackendDelegate : public HistoryBackend::Delegate {
132 const base::WeakPtr<HistoryService>& history_service,
133 const scoped_refptr<base::SequencedTaskRunner>& service_task_runner,
135 : history_service_(history_service),
136 service_task_runner_(service_task_runner),
140 void NotifyProfileError(sql::InitStatus init_status) override {
141 // Send to the history service on the main thread.
142 service_task_runner_->PostTask(
144 base::Bind(&HistoryService::NotifyProfileError, history_service_,
148 void SetInMemoryBackend(
149 scoped_ptr<history::InMemoryHistoryBackend> backend) override {
150 // Send the backend to the history service on the main thread.
151 service_task_runner_->PostTask(
153 base::Bind(&HistoryService::SetInMemoryBackend, history_service_,
154 base::Passed(&backend)));
157 void NotifyAddVisit(const history::BriefVisitInfo& info) override {
158 service_task_runner_->PostTask(
160 base::Bind(&HistoryService::NotifyAddVisit, history_service_, info));
163 void NotifyFaviconChanged(const std::set<GURL>& urls) override {
164 // Send the notification to the history service on the main thread.
165 service_task_runner_->PostTask(
168 &HistoryService::NotifyFaviconChanged, history_service_, urls));
171 void NotifyURLVisited(ui::PageTransition transition,
172 const history::URLRow& row,
173 const history::RedirectList& redirects,
174 base::Time visit_time) override {
175 service_task_runner_->PostTask(FROM_HERE,
176 base::Bind(&HistoryService::NotifyURLVisited,
184 void BroadcastNotifications(
186 scoped_ptr<history::HistoryDetails> details) override {
187 // Send the notification on the history thread.
188 if (content::NotificationService::current()) {
189 content::Details<history::HistoryDetails> det(details.get());
190 content::NotificationService::current()->Notify(
191 type, content::Source<Profile>(profile_), det);
193 // Send the notification to the history service on the main thread.
194 service_task_runner_->PostTask(
196 base::Bind(&HistoryService::BroadcastNotificationsHelper,
197 history_service_, type, base::Passed(&details)));
200 void DBLoaded() override {
201 service_task_runner_->PostTask(
203 base::Bind(&HistoryService::OnDBLoaded, history_service_));
207 const base::WeakPtr<HistoryService> history_service_;
208 const scoped_refptr<base::SequencedTaskRunner> service_task_runner_;
209 Profile* const profile_;
212 // The history thread is intentionally not a BrowserThread because the
213 // sync integration unit tests depend on being able to create more than one
215 HistoryService::HistoryService()
216 : thread_(new base::Thread(kHistoryThreadName)),
217 history_client_(NULL),
219 backend_loaded_(false),
221 weak_ptr_factory_(this) {
224 HistoryService::HistoryService(history::HistoryClient* client, Profile* profile)
225 : thread_(new base::Thread(kHistoryThreadName)),
226 history_client_(client),
228 visitedlink_master_(new visitedlink::VisitedLinkMaster(
229 profile, this, true)),
230 backend_loaded_(false),
232 weak_ptr_factory_(this) {
234 registrar_.Add(this, chrome::NOTIFICATION_HISTORY_URLS_DELETED,
235 content::Source<Profile>(profile_));
238 HistoryService::~HistoryService() {
239 DCHECK(thread_checker_.CalledOnValidThread());
240 // Shutdown the backend. This does nothing if Cleanup was already invoked.
244 bool HistoryService::BackendLoaded() {
245 DCHECK(thread_checker_.CalledOnValidThread());
246 return backend_loaded_;
249 void HistoryService::ClearCachedDataForContextID(
250 history::ContextID context_id) {
251 DCHECK(thread_) << "History service being called after cleanup";
252 DCHECK(thread_checker_.CalledOnValidThread());
253 ScheduleAndForget(PRIORITY_NORMAL,
254 &HistoryBackend::ClearCachedDataForContextID, context_id);
257 history::URLDatabase* HistoryService::InMemoryDatabase() {
258 DCHECK(thread_checker_.CalledOnValidThread());
259 return in_memory_backend_ ? in_memory_backend_->db() : NULL;
262 bool HistoryService::GetTypedCountForURL(const GURL& url, int* typed_count) {
263 DCHECK(thread_checker_.CalledOnValidThread());
264 history::URLRow url_row;
265 if (!GetRowForURL(url, &url_row))
267 *typed_count = url_row.typed_count();
271 bool HistoryService::GetLastVisitTimeForURL(const GURL& url,
272 base::Time* last_visit) {
273 DCHECK(thread_checker_.CalledOnValidThread());
274 history::URLRow url_row;
275 if (!GetRowForURL(url, &url_row))
277 *last_visit = url_row.last_visit();
281 bool HistoryService::GetVisitCountForURL(const GURL& url, int* visit_count) {
282 DCHECK(thread_checker_.CalledOnValidThread());
283 history::URLRow url_row;
284 if (!GetRowForURL(url, &url_row))
286 *visit_count = url_row.visit_count();
290 history::TypedUrlSyncableService* HistoryService::GetTypedUrlSyncableService()
292 return history_backend_->GetTypedUrlSyncableService();
295 void HistoryService::Shutdown() {
296 DCHECK(thread_checker_.CalledOnValidThread());
300 void HistoryService::SetKeywordSearchTermsForURL(const GURL& url,
301 KeywordID keyword_id,
302 const base::string16& term) {
303 DCHECK(thread_) << "History service being called after cleanup";
304 DCHECK(thread_checker_.CalledOnValidThread());
305 ScheduleAndForget(PRIORITY_UI,
306 &HistoryBackend::SetKeywordSearchTermsForURL,
307 url, keyword_id, term);
310 void HistoryService::DeleteAllSearchTermsForKeyword(KeywordID keyword_id) {
311 DCHECK(thread_) << "History service being called after cleanup";
312 DCHECK(thread_checker_.CalledOnValidThread());
314 if (in_memory_backend_)
315 in_memory_backend_->DeleteAllSearchTermsForKeyword(keyword_id);
317 ScheduleAndForget(PRIORITY_UI,
318 &HistoryBackend::DeleteAllSearchTermsForKeyword,
322 void HistoryService::DeleteKeywordSearchTermForURL(const GURL& url) {
323 DCHECK(thread_) << "History service being called after cleanup";
324 DCHECK(thread_checker_.CalledOnValidThread());
325 ScheduleAndForget(PRIORITY_UI, &HistoryBackend::DeleteKeywordSearchTermForURL,
329 void HistoryService::DeleteMatchingURLsForKeyword(KeywordID keyword_id,
330 const base::string16& term) {
331 DCHECK(thread_) << "History service being called after cleanup";
332 DCHECK(thread_checker_.CalledOnValidThread());
333 ScheduleAndForget(PRIORITY_UI, &HistoryBackend::DeleteMatchingURLsForKeyword,
337 void HistoryService::URLsNoLongerBookmarked(const std::set<GURL>& urls) {
338 DCHECK(thread_) << "History service being called after cleanup";
339 DCHECK(thread_checker_.CalledOnValidThread());
340 ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::URLsNoLongerBookmarked,
344 void HistoryService::AddObserver(history::HistoryServiceObserver* observer) {
345 DCHECK(thread_checker_.CalledOnValidThread());
346 observers_.AddObserver(observer);
349 void HistoryService::RemoveObserver(history::HistoryServiceObserver* observer) {
350 DCHECK(thread_checker_.CalledOnValidThread());
351 observers_.RemoveObserver(observer);
354 void HistoryService::ScheduleDBTask(scoped_ptr<history::HistoryDBTask> task,
355 base::CancelableTaskTracker* tracker) {
356 DCHECK(thread_) << "History service being called after cleanup";
357 DCHECK(thread_checker_.CalledOnValidThread());
358 base::CancelableTaskTracker::IsCanceledCallback is_canceled;
359 tracker->NewTrackedTaskId(&is_canceled);
360 // Use base::ThreadTaskRunnerHandler::Get() to get a message loop proxy to
361 // the current message loop so that we can forward the call to the method
362 // HistoryDBTask::DoneRunOnMainThread in the correct thread.
363 thread_->message_loop_proxy()->PostTask(
365 base::Bind(&HistoryBackend::ProcessDBTask,
366 history_backend_.get(),
368 base::ThreadTaskRunnerHandle::Get(),
372 void HistoryService::FlushForTest(const base::Closure& flushed) {
373 thread_->message_loop_proxy()->PostTaskAndReply(
374 FROM_HERE, base::Bind(&base::DoNothing), flushed);
377 void HistoryService::SetOnBackendDestroyTask(const base::Closure& task) {
378 DCHECK(thread_) << "History service being called after cleanup";
379 DCHECK(thread_checker_.CalledOnValidThread());
380 ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::SetOnBackendDestroyTask,
381 base::MessageLoop::current(), task);
384 void HistoryService::AddPage(const GURL& url,
386 history::ContextID context_id,
388 const GURL& referrer,
389 const history::RedirectList& redirects,
390 ui::PageTransition transition,
391 history::VisitSource visit_source,
392 bool did_replace_entry) {
393 DCHECK(thread_checker_.CalledOnValidThread());
395 history::HistoryAddPageArgs(url, time, context_id, page_id, referrer,
396 redirects, transition, visit_source,
400 void HistoryService::AddPage(const GURL& url,
402 history::VisitSource visit_source) {
403 DCHECK(thread_checker_.CalledOnValidThread());
405 history::HistoryAddPageArgs(url, time, NULL, 0, GURL(),
406 history::RedirectList(),
407 ui::PAGE_TRANSITION_LINK,
408 visit_source, false));
411 void HistoryService::AddPage(const history::HistoryAddPageArgs& add_page_args) {
412 DCHECK(thread_) << "History service being called after cleanup";
413 DCHECK(thread_checker_.CalledOnValidThread());
415 // Filter out unwanted URLs. We don't add auto-subframe URLs. They are a
416 // large part of history (think iframes for ads) and we never display them in
417 // history UI. We will still add manual subframes, which are ones the user
418 // has clicked on to get.
419 if (!CanAddURL(add_page_args.url))
422 // Add link & all redirects to visited link list.
423 if (visitedlink_master_) {
424 visitedlink_master_->AddURL(add_page_args.url);
426 if (!add_page_args.redirects.empty()) {
427 // We should not be asked to add a page in the middle of a redirect chain.
428 DCHECK_EQ(add_page_args.url,
429 add_page_args.redirects[add_page_args.redirects.size() - 1]);
431 // We need the !redirects.empty() condition above since size_t is unsigned
432 // and will wrap around when we subtract one from a 0 size.
433 for (size_t i = 0; i < add_page_args.redirects.size() - 1; i++)
434 visitedlink_master_->AddURL(add_page_args.redirects[i]);
438 ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::AddPage, add_page_args);
441 void HistoryService::AddPageNoVisitForBookmark(const GURL& url,
442 const base::string16& title) {
443 DCHECK(thread_) << "History service being called after cleanup";
444 DCHECK(thread_checker_.CalledOnValidThread());
448 ScheduleAndForget(PRIORITY_NORMAL,
449 &HistoryBackend::AddPageNoVisitForBookmark, url, title);
452 void HistoryService::SetPageTitle(const GURL& url,
453 const base::string16& title) {
454 DCHECK(thread_) << "History service being called after cleanup";
455 DCHECK(thread_checker_.CalledOnValidThread());
456 ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::SetPageTitle, url, title);
459 void HistoryService::UpdateWithPageEndTime(history::ContextID context_id,
463 DCHECK(thread_) << "History service being called after cleanup";
464 DCHECK(thread_checker_.CalledOnValidThread());
465 ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::UpdateWithPageEndTime,
466 context_id, page_id, url, end_ts);
469 void HistoryService::AddPageWithDetails(const GURL& url,
470 const base::string16& title,
475 history::VisitSource visit_source) {
476 DCHECK(thread_) << "History service being called after cleanup";
477 DCHECK(thread_checker_.CalledOnValidThread());
478 // Filter out unwanted URLs.
482 // Add to the visited links system.
483 if (visitedlink_master_)
484 visitedlink_master_->AddURL(url);
486 history::URLRow row(url);
487 row.set_title(title);
488 row.set_visit_count(visit_count);
489 row.set_typed_count(typed_count);
490 row.set_last_visit(last_visit);
491 row.set_hidden(hidden);
493 history::URLRows rows;
496 ScheduleAndForget(PRIORITY_NORMAL,
497 &HistoryBackend::AddPagesWithDetails, rows, visit_source);
500 void HistoryService::AddPagesWithDetails(const history::URLRows& info,
501 history::VisitSource visit_source) {
502 DCHECK(thread_) << "History service being called after cleanup";
503 DCHECK(thread_checker_.CalledOnValidThread());
504 // Add to the visited links system.
505 if (visitedlink_master_) {
506 std::vector<GURL> urls;
507 urls.reserve(info.size());
508 for (history::URLRows::const_iterator i = info.begin(); i != info.end();
510 urls.push_back(i->url());
512 visitedlink_master_->AddURLs(urls);
515 ScheduleAndForget(PRIORITY_NORMAL,
516 &HistoryBackend::AddPagesWithDetails, info, visit_source);
519 base::CancelableTaskTracker::TaskId HistoryService::GetFavicons(
520 const std::vector<GURL>& icon_urls,
522 const std::vector<int>& desired_sizes,
523 const favicon_base::FaviconResultsCallback& callback,
524 base::CancelableTaskTracker* tracker) {
525 DCHECK(thread_) << "History service being called after cleanup";
526 DCHECK(thread_checker_.CalledOnValidThread());
527 std::vector<favicon_base::FaviconRawBitmapResult>* results =
528 new std::vector<favicon_base::FaviconRawBitmapResult>();
529 return tracker->PostTaskAndReply(
530 thread_->message_loop_proxy().get(),
532 base::Bind(&HistoryBackend::GetFavicons,
533 history_backend_.get(),
538 base::Bind(&RunWithFaviconResults, callback, base::Owned(results)));
541 base::CancelableTaskTracker::TaskId HistoryService::GetFaviconsForURL(
542 const GURL& page_url,
544 const std::vector<int>& desired_sizes,
545 const favicon_base::FaviconResultsCallback& callback,
546 base::CancelableTaskTracker* tracker) {
547 DCHECK(thread_) << "History service being called after cleanup";
548 DCHECK(thread_checker_.CalledOnValidThread());
549 std::vector<favicon_base::FaviconRawBitmapResult>* results =
550 new std::vector<favicon_base::FaviconRawBitmapResult>();
551 return tracker->PostTaskAndReply(
552 thread_->message_loop_proxy().get(),
554 base::Bind(&HistoryBackend::GetFaviconsForURL,
555 history_backend_.get(),
560 base::Bind(&RunWithFaviconResults, callback, base::Owned(results)));
563 base::CancelableTaskTracker::TaskId HistoryService::GetLargestFaviconForURL(
564 const GURL& page_url,
565 const std::vector<int>& icon_types,
566 int minimum_size_in_pixels,
567 const favicon_base::FaviconRawBitmapCallback& callback,
568 base::CancelableTaskTracker* tracker) {
569 DCHECK(thread_) << "History service being called after cleanup";
570 DCHECK(thread_checker_.CalledOnValidThread());
571 favicon_base::FaviconRawBitmapResult* result =
572 new favicon_base::FaviconRawBitmapResult();
573 return tracker->PostTaskAndReply(
574 thread_->message_loop_proxy().get(),
576 base::Bind(&HistoryBackend::GetLargestFaviconForURL,
577 history_backend_.get(),
580 minimum_size_in_pixels,
582 base::Bind(&RunWithFaviconResult, callback, base::Owned(result)));
585 base::CancelableTaskTracker::TaskId HistoryService::GetFaviconForID(
586 favicon_base::FaviconID favicon_id,
588 const favicon_base::FaviconResultsCallback& callback,
589 base::CancelableTaskTracker* tracker) {
590 DCHECK(thread_) << "History service being called after cleanup";
591 DCHECK(thread_checker_.CalledOnValidThread());
592 std::vector<favicon_base::FaviconRawBitmapResult>* results =
593 new std::vector<favicon_base::FaviconRawBitmapResult>();
594 return tracker->PostTaskAndReply(
595 thread_->message_loop_proxy().get(),
597 base::Bind(&HistoryBackend::GetFaviconForID,
598 history_backend_.get(),
602 base::Bind(&RunWithFaviconResults, callback, base::Owned(results)));
605 base::CancelableTaskTracker::TaskId
606 HistoryService::UpdateFaviconMappingsAndFetch(
607 const GURL& page_url,
608 const std::vector<GURL>& icon_urls,
610 const std::vector<int>& desired_sizes,
611 const favicon_base::FaviconResultsCallback& callback,
612 base::CancelableTaskTracker* tracker) {
613 DCHECK(thread_) << "History service being called after cleanup";
614 DCHECK(thread_checker_.CalledOnValidThread());
615 std::vector<favicon_base::FaviconRawBitmapResult>* results =
616 new std::vector<favicon_base::FaviconRawBitmapResult>();
617 return tracker->PostTaskAndReply(
618 thread_->message_loop_proxy().get(),
620 base::Bind(&HistoryBackend::UpdateFaviconMappingsAndFetch,
621 history_backend_.get(),
627 base::Bind(&RunWithFaviconResults, callback, base::Owned(results)));
630 void HistoryService::MergeFavicon(
631 const GURL& page_url,
632 const GURL& icon_url,
633 favicon_base::IconType icon_type,
634 scoped_refptr<base::RefCountedMemory> bitmap_data,
635 const gfx::Size& pixel_size) {
636 DCHECK(thread_) << "History service being called after cleanup";
637 DCHECK(thread_checker_.CalledOnValidThread());
638 if (!CanAddURL(page_url))
641 ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::MergeFavicon, page_url,
642 icon_url, icon_type, bitmap_data, pixel_size);
645 void HistoryService::SetFavicons(
646 const GURL& page_url,
647 favicon_base::IconType icon_type,
648 const GURL& icon_url,
649 const std::vector<SkBitmap>& bitmaps) {
650 DCHECK(thread_) << "History service being called after cleanup";
651 DCHECK(thread_checker_.CalledOnValidThread());
652 if (!CanAddURL(page_url))
655 ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::SetFavicons, page_url,
656 icon_type, icon_url, bitmaps);
659 void HistoryService::SetFaviconsOutOfDateForPage(const GURL& page_url) {
660 DCHECK(thread_) << "History service being called after cleanup";
661 DCHECK(thread_checker_.CalledOnValidThread());
662 ScheduleAndForget(PRIORITY_NORMAL,
663 &HistoryBackend::SetFaviconsOutOfDateForPage, page_url);
666 void HistoryService::CloneFavicons(const GURL& old_page_url,
667 const GURL& new_page_url) {
668 DCHECK(thread_) << "History service being called after cleanup";
669 DCHECK(thread_checker_.CalledOnValidThread());
670 ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::CloneFavicons,
671 old_page_url, new_page_url);
674 void HistoryService::SetImportedFavicons(
675 const std::vector<ImportedFaviconUsage>& favicon_usage) {
676 DCHECK(thread_) << "History service being called after cleanup";
677 DCHECK(thread_checker_.CalledOnValidThread());
678 ScheduleAndForget(PRIORITY_NORMAL,
679 &HistoryBackend::SetImportedFavicons, favicon_usage);
682 base::CancelableTaskTracker::TaskId HistoryService::QueryURL(
685 const QueryURLCallback& callback,
686 base::CancelableTaskTracker* tracker) {
687 DCHECK(thread_) << "History service being called after cleanup";
688 DCHECK(thread_checker_.CalledOnValidThread());
689 history::QueryURLResult* query_url_result = new history::QueryURLResult();
690 return tracker->PostTaskAndReply(
691 thread_->message_loop_proxy().get(),
693 base::Bind(&HistoryBackend::QueryURL,
694 history_backend_.get(),
697 base::Unretained(query_url_result)),
699 &RunWithQueryURLResult, callback, base::Owned(query_url_result)));
702 // Downloads -------------------------------------------------------------------
704 // Handle creation of a download by creating an entry in the history service's
705 // 'downloads' table.
706 void HistoryService::CreateDownload(
707 const history::DownloadRow& create_info,
708 const HistoryService::DownloadCreateCallback& callback) {
709 DCHECK(thread_) << "History service being called after cleanup";
710 DCHECK(thread_checker_.CalledOnValidThread());
711 PostTaskAndReplyWithResult(
712 thread_->message_loop_proxy().get(),
715 &HistoryBackend::CreateDownload, history_backend_.get(), create_info),
719 void HistoryService::GetNextDownloadId(
720 const content::DownloadIdCallback& callback) {
721 DCHECK(thread_) << "History service being called after cleanup";
722 DCHECK(thread_checker_.CalledOnValidThread());
723 PostTaskAndReplyWithResult(
724 thread_->message_loop_proxy().get(),
726 base::Bind(&HistoryBackend::GetNextDownloadId, history_backend_.get()),
730 // Handle queries for a list of all downloads in the history database's
731 // 'downloads' table.
732 void HistoryService::QueryDownloads(
733 const DownloadQueryCallback& callback) {
734 DCHECK(thread_) << "History service being called after cleanup";
735 DCHECK(thread_checker_.CalledOnValidThread());
736 std::vector<history::DownloadRow>* rows =
737 new std::vector<history::DownloadRow>();
738 scoped_ptr<std::vector<history::DownloadRow> > scoped_rows(rows);
739 // Beware! The first Bind() does not simply |scoped_rows.get()| because
740 // base::Passed(&scoped_rows) nullifies |scoped_rows|, and compilers do not
741 // guarantee that the first Bind's arguments are evaluated before the second
743 thread_->message_loop_proxy()->PostTaskAndReply(
745 base::Bind(&HistoryBackend::QueryDownloads, history_backend_.get(), rows),
746 base::Bind(callback, base::Passed(&scoped_rows)));
749 // Handle updates for a particular download. This is a 'fire and forget'
750 // operation, so we don't need to be called back.
751 void HistoryService::UpdateDownload(const history::DownloadRow& data) {
752 DCHECK(thread_) << "History service being called after cleanup";
753 DCHECK(thread_checker_.CalledOnValidThread());
754 ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::UpdateDownload, data);
757 void HistoryService::RemoveDownloads(const std::set<uint32>& ids) {
758 DCHECK(thread_) << "History service being called after cleanup";
759 DCHECK(thread_checker_.CalledOnValidThread());
760 ScheduleAndForget(PRIORITY_NORMAL,
761 &HistoryBackend::RemoveDownloads, ids);
764 base::CancelableTaskTracker::TaskId HistoryService::QueryHistory(
765 const base::string16& text_query,
766 const history::QueryOptions& options,
767 const QueryHistoryCallback& callback,
768 base::CancelableTaskTracker* tracker) {
769 DCHECK(thread_) << "History service being called after cleanup";
770 DCHECK(thread_checker_.CalledOnValidThread());
771 history::QueryResults* query_results = new history::QueryResults();
772 return tracker->PostTaskAndReply(
773 thread_->message_loop_proxy().get(),
775 base::Bind(&HistoryBackend::QueryHistory,
776 history_backend_.get(),
779 base::Unretained(query_results)),
780 base::Bind(callback, base::Owned(query_results)));
783 base::CancelableTaskTracker::TaskId HistoryService::QueryRedirectsFrom(
784 const GURL& from_url,
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(
791 thread_->message_loop_proxy().get(),
793 base::Bind(&HistoryBackend::QueryRedirectsFrom,
794 history_backend_.get(),
796 base::Unretained(result)),
797 base::Bind(callback, base::Owned(result)));
800 base::CancelableTaskTracker::TaskId HistoryService::QueryRedirectsTo(
802 const QueryRedirectsCallback& callback,
803 base::CancelableTaskTracker* tracker) {
804 DCHECK(thread_) << "History service being called after cleanup";
805 DCHECK(thread_checker_.CalledOnValidThread());
806 history::RedirectList* result = new history::RedirectList();
807 return tracker->PostTaskAndReply(thread_->message_loop_proxy().get(),
809 base::Bind(&HistoryBackend::QueryRedirectsTo,
810 history_backend_.get(),
812 base::Unretained(result)),
813 base::Bind(callback, base::Owned(result)));
816 base::CancelableTaskTracker::TaskId HistoryService::GetVisibleVisitCountToHost(
818 const GetVisibleVisitCountToHostCallback& callback,
819 base::CancelableTaskTracker* tracker) {
820 DCHECK(thread_) << "History service being called after cleanup";
821 DCHECK(thread_checker_.CalledOnValidThread());
822 history::VisibleVisitCountToHostResult* result =
823 new history::VisibleVisitCountToHostResult();
824 return tracker->PostTaskAndReply(
825 thread_->message_loop_proxy().get(),
827 base::Bind(&HistoryBackend::GetVisibleVisitCountToHost,
828 history_backend_.get(),
830 base::Unretained(result)),
831 base::Bind(&RunWithVisibleVisitCountToHostResult,
833 base::Owned(result)));
836 base::CancelableTaskTracker::TaskId HistoryService::QueryMostVisitedURLs(
839 const QueryMostVisitedURLsCallback& callback,
840 base::CancelableTaskTracker* tracker) {
841 DCHECK(thread_) << "History service being called after cleanup";
842 DCHECK(thread_checker_.CalledOnValidThread());
843 history::MostVisitedURLList* result = new history::MostVisitedURLList();
844 return tracker->PostTaskAndReply(
845 thread_->message_loop_proxy().get(),
847 base::Bind(&HistoryBackend::QueryMostVisitedURLs,
848 history_backend_.get(),
851 base::Unretained(result)),
852 base::Bind(callback, base::Owned(result)));
855 base::CancelableTaskTracker::TaskId HistoryService::QueryFilteredURLs(
857 const history::VisitFilter& filter,
859 const QueryFilteredURLsCallback& callback,
860 base::CancelableTaskTracker* tracker) {
861 DCHECK(thread_) << "History service being called after cleanup";
862 DCHECK(thread_checker_.CalledOnValidThread());
863 history::FilteredURLList* result = new history::FilteredURLList();
864 return tracker->PostTaskAndReply(
865 thread_->message_loop_proxy().get(),
867 base::Bind(&HistoryBackend::QueryFilteredURLs,
868 history_backend_.get(),
872 base::Unretained(result)),
873 base::Bind(callback, base::Owned(result)));
876 void HistoryService::Cleanup() {
877 DCHECK(thread_checker_.CalledOnValidThread());
879 // We've already cleaned up.
883 weak_ptr_factory_.InvalidateWeakPtrs();
885 // Unload the backend.
886 if (history_backend_.get()) {
887 // Get rid of the in-memory backend.
888 in_memory_backend_.reset();
890 // Give the InMemoryURLIndex a chance to shutdown.
891 // NOTE: In tests, there may be no index.
892 if (in_memory_url_index_)
893 in_memory_url_index_->ShutDown();
895 // The backend's destructor must run on the history thread since it is not
896 // threadsafe. So this thread must not be the last thread holding a
897 // reference to the backend, or a crash could happen.
899 // We have a reference to the history backend. There is also an extra
900 // reference held by our delegate installed in the backend, which
901 // HistoryBackend::Closing will release. This means if we scheduled a call
902 // to HistoryBackend::Closing and *then* released our backend reference,
903 // there will be a race between us and the backend's Closing function to see
904 // who is the last holder of a reference. If the backend thread's Closing
905 // manages to run before we release our backend refptr, the last reference
906 // will be held by this thread and the destructor will be called from here.
908 // Therefore, we create a closure to run the Closing operation first. This
909 // holds a reference to the backend. Then we release our reference, then we
910 // schedule the task to run. After the task runs, it will delete its
911 // reference from the history thread, ensuring everything works properly.
913 // TODO(ajwong): Cleanup HistoryBackend lifetime issues.
914 // See http://crbug.com/99767.
915 history_backend_->AddRef();
916 base::Closure closing_task =
917 base::Bind(&HistoryBackend::Closing, history_backend_.get());
918 ScheduleTask(PRIORITY_NORMAL, closing_task);
919 closing_task.Reset();
920 HistoryBackend* raw_ptr = history_backend_.get();
921 history_backend_ = NULL;
922 thread_->message_loop()->ReleaseSoon(FROM_HERE, raw_ptr);
925 // Delete the thread, which joins with the background thread. We defensively
926 // NULL the pointer before deleting it in case somebody tries to use it
927 // during shutdown, but this shouldn't happen.
928 base::Thread* thread = thread_;
933 void HistoryService::Observe(int type,
934 const content::NotificationSource& source,
935 const content::NotificationDetails& details) {
936 DCHECK(thread_checker_.CalledOnValidThread());
941 case chrome::NOTIFICATION_HISTORY_URLS_DELETED: {
942 // Update the visited link system for deleted URLs. We will update the
943 // visited link system for added URLs as soon as we get the add
944 // notification (we don't have to wait for the backend, which allows us to
945 // be faster to update the state).
947 // For deleted URLs, we don't typically know what will be deleted since
948 // delete notifications are by time. We would also like to be more
949 // respectful of privacy and never tell the user something is gone when it
950 // isn't. Therefore, we update the delete URLs after the fact.
951 if (visitedlink_master_) {
952 content::Details<history::URLsDeletedDetails> deleted_details(details);
954 if (deleted_details->all_history) {
955 visitedlink_master_->DeleteAllURLs();
957 URLIteratorFromURLRows iterator(deleted_details->rows);
958 visitedlink_master_->DeleteURLs(&iterator);
969 void HistoryService::RebuildTable(
970 const scoped_refptr<URLEnumerator>& enumerator) {
971 DCHECK(thread_) << "History service being called after cleanup";
972 DCHECK(thread_checker_.CalledOnValidThread());
973 ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::IterateURLs, enumerator);
976 bool HistoryService::Init(const base::FilePath& history_dir, bool no_db) {
977 DCHECK(thread_) << "History service being called after cleanup";
978 DCHECK(thread_checker_.CalledOnValidThread());
979 base::Thread::Options options;
980 options.timer_slack = base::TIMER_SLACK_MAXIMUM;
981 if (!thread_->StartWithOptions(options)) {
986 history_dir_ = history_dir;
990 std::string languages =
991 profile_->GetPrefs()->GetString(prefs::kAcceptLanguages);
992 in_memory_url_index_.reset(new history::InMemoryURLIndex(
993 profile_, this, history_dir_, languages, history_client_));
994 in_memory_url_index_->Init();
997 // Create the history backend.
998 scoped_refptr<HistoryBackend> backend(
999 new HistoryBackend(history_dir_,
1000 new BackendDelegate(
1001 weak_ptr_factory_.GetWeakPtr(),
1002 base::ThreadTaskRunnerHandle::Get(),
1005 history_backend_.swap(backend);
1007 // There may not be a profile when unit testing.
1008 std::string languages;
1010 PrefService* prefs = profile_->GetPrefs();
1011 languages = prefs->GetString(prefs::kAcceptLanguages);
1013 ScheduleAndForget(PRIORITY_UI, &HistoryBackend::Init, languages, no_db_);
1015 if (visitedlink_master_) {
1016 bool result = visitedlink_master_->Init();
1023 void HistoryService::ScheduleAutocomplete(const base::Callback<
1024 void(history::HistoryBackend*, history::URLDatabase*)>& callback) {
1025 DCHECK(thread_checker_.CalledOnValidThread());
1027 PRIORITY_UI, &HistoryBackend::ScheduleAutocomplete, callback);
1030 void HistoryService::ScheduleTask(SchedulePriority priority,
1031 const base::Closure& task) {
1032 DCHECK(thread_checker_.CalledOnValidThread());
1034 CHECK(thread_->message_loop());
1035 // TODO(brettw): Do prioritization.
1036 thread_->message_loop()->PostTask(FROM_HERE, task);
1040 bool HistoryService::CanAddURL(const GURL& url) {
1041 if (!url.is_valid())
1044 // TODO: We should allow kChromeUIScheme URLs if they have been explicitly
1045 // typed. Right now, however, these are marked as typed even when triggered
1046 // by a shortcut or menu action.
1047 if (url.SchemeIs(url::kJavaScriptScheme) ||
1048 url.SchemeIs(content::kChromeDevToolsScheme) ||
1049 url.SchemeIs(content::kChromeUIScheme) ||
1050 url.SchemeIs(content::kViewSourceScheme) ||
1051 url.SchemeIs(chrome::kChromeNativeScheme) ||
1052 url.SchemeIs(chrome::kChromeSearchScheme) ||
1053 url.SchemeIs(dom_distiller::kDomDistillerScheme))
1056 // Allow all about: and chrome: URLs except about:blank, since the user may
1057 // like to see "chrome://memory/", etc. in their history and autocomplete.
1058 if (url == GURL(url::kAboutBlankURL))
1064 base::WeakPtr<HistoryService> HistoryService::AsWeakPtr() {
1065 DCHECK(thread_checker_.CalledOnValidThread());
1066 return weak_ptr_factory_.GetWeakPtr();
1069 syncer::SyncMergeResult HistoryService::MergeDataAndStartSyncing(
1070 syncer::ModelType type,
1071 const syncer::SyncDataList& initial_sync_data,
1072 scoped_ptr<syncer::SyncChangeProcessor> sync_processor,
1073 scoped_ptr<syncer::SyncErrorFactory> error_handler) {
1074 DCHECK(thread_checker_.CalledOnValidThread());
1075 DCHECK_EQ(type, syncer::HISTORY_DELETE_DIRECTIVES);
1076 delete_directive_handler_.Start(this, initial_sync_data,
1077 sync_processor.Pass());
1078 return syncer::SyncMergeResult(type);
1081 void HistoryService::StopSyncing(syncer::ModelType type) {
1082 DCHECK(thread_checker_.CalledOnValidThread());
1083 DCHECK_EQ(type, syncer::HISTORY_DELETE_DIRECTIVES);
1084 delete_directive_handler_.Stop();
1087 syncer::SyncDataList HistoryService::GetAllSyncData(
1088 syncer::ModelType type) const {
1089 DCHECK(thread_checker_.CalledOnValidThread());
1090 DCHECK_EQ(type, syncer::HISTORY_DELETE_DIRECTIVES);
1091 // TODO(akalin): Keep track of existing delete directives.
1092 return syncer::SyncDataList();
1095 syncer::SyncError HistoryService::ProcessSyncChanges(
1096 const tracked_objects::Location& from_here,
1097 const syncer::SyncChangeList& change_list) {
1098 delete_directive_handler_.ProcessSyncChanges(this, change_list);
1099 return syncer::SyncError();
1102 syncer::SyncError HistoryService::ProcessLocalDeleteDirective(
1103 const sync_pb::HistoryDeleteDirectiveSpecifics& delete_directive) {
1104 DCHECK(thread_checker_.CalledOnValidThread());
1105 return delete_directive_handler_.ProcessLocalDeleteDirective(
1109 void HistoryService::SetInMemoryBackend(
1110 scoped_ptr<history::InMemoryHistoryBackend> mem_backend) {
1111 DCHECK(thread_checker_.CalledOnValidThread());
1112 DCHECK(!in_memory_backend_) << "Setting mem DB twice";
1113 in_memory_backend_.reset(mem_backend.release());
1115 // The database requires additional initialization once we own it.
1116 in_memory_backend_->AttachToHistoryService(profile_, this);
1119 void HistoryService::NotifyProfileError(sql::InitStatus init_status) {
1120 DCHECK(thread_checker_.CalledOnValidThread());
1121 if (history_client_)
1122 history_client_->NotifyProfileError(init_status);
1125 void HistoryService::DeleteURL(const GURL& url) {
1126 DCHECK(thread_) << "History service being called after cleanup";
1127 DCHECK(thread_checker_.CalledOnValidThread());
1128 // We will update the visited links when we observe the delete notifications.
1129 ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::DeleteURL, url);
1132 void HistoryService::DeleteURLsForTest(const std::vector<GURL>& urls) {
1133 DCHECK(thread_) << "History service being called after cleanup";
1134 DCHECK(thread_checker_.CalledOnValidThread());
1135 // We will update the visited links when we observe the delete
1137 ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::DeleteURLs, urls);
1140 void HistoryService::ExpireHistoryBetween(
1141 const std::set<GURL>& restrict_urls,
1144 const base::Closure& callback,
1145 base::CancelableTaskTracker* tracker) {
1146 DCHECK(thread_) << "History service being called after cleanup";
1147 DCHECK(thread_checker_.CalledOnValidThread());
1148 tracker->PostTaskAndReply(thread_->message_loop_proxy().get(),
1150 base::Bind(&HistoryBackend::ExpireHistoryBetween,
1158 void HistoryService::ExpireHistory(
1159 const std::vector<history::ExpireHistoryArgs>& expire_list,
1160 const base::Closure& callback,
1161 base::CancelableTaskTracker* tracker) {
1162 DCHECK(thread_) << "History service being called after cleanup";
1163 DCHECK(thread_checker_.CalledOnValidThread());
1164 tracker->PostTaskAndReply(
1165 thread_->message_loop_proxy().get(),
1167 base::Bind(&HistoryBackend::ExpireHistory, history_backend_, expire_list),
1171 void HistoryService::ExpireLocalAndRemoteHistoryBetween(
1172 const std::set<GURL>& restrict_urls,
1175 const base::Closure& callback,
1176 base::CancelableTaskTracker* tracker) {
1177 // TODO(dubroy): This should be factored out into a separate class that
1178 // dispatches deletions to the proper places.
1180 history::WebHistoryService* web_history =
1181 WebHistoryServiceFactory::GetForProfile(profile_);
1183 // TODO(dubroy): This API does not yet support deletion of specific URLs.
1184 DCHECK(restrict_urls.empty());
1186 delete_directive_handler_.CreateDeleteDirectives(
1187 std::set<int64>(), begin_time, end_time);
1189 // Attempt online deletion from the history server, but ignore the result.
1190 // Deletion directives ensure that the results will eventually be deleted.
1192 // TODO(davidben): |callback| should not run until this operation completes
1194 web_history->ExpireHistoryBetween(
1195 restrict_urls, begin_time, end_time,
1196 base::Bind(&ExpireWebHistoryComplete));
1198 ExpireHistoryBetween(restrict_urls, begin_time, end_time, callback, tracker);
1201 void HistoryService::BroadcastNotificationsHelper(
1203 scoped_ptr<history::HistoryDetails> details) {
1204 DCHECK(thread_checker_.CalledOnValidThread());
1205 // TODO(evanm): this is currently necessitated by generate_profile, which
1206 // runs without a browser process. generate_profile should really create
1207 // a browser process, at which point this check can then be nuked.
1208 if (!g_browser_process)
1214 // The source of all of our notifications is the profile. Note that this
1215 // pointer is NULL in unit tests.
1216 content::Source<Profile> source(profile_);
1218 // The details object just contains the pointer to the object that the
1219 // backend has allocated for us. The receiver of the notification will cast
1220 // this to the proper type.
1221 content::Details<history::HistoryDetails> det(details.get());
1223 content::NotificationService::current()->Notify(type, source, det);
1226 void HistoryService::OnDBLoaded() {
1227 DCHECK(thread_checker_.CalledOnValidThread());
1228 backend_loaded_ = true;
1229 content::NotificationService::current()->Notify(
1230 chrome::NOTIFICATION_HISTORY_LOADED,
1231 content::Source<Profile>(profile_),
1232 content::Details<HistoryService>(this));
1235 bool HistoryService::GetRowForURL(const GURL& url, history::URLRow* url_row) {
1236 DCHECK(thread_checker_.CalledOnValidThread());
1237 history::URLDatabase* db = InMemoryDatabase();
1238 return db && (db->GetRowForURL(url, url_row) != 0);
1241 void HistoryService::NotifyAddVisit(const history::BriefVisitInfo& info) {
1242 DCHECK(thread_checker_.CalledOnValidThread());
1244 history::HistoryServiceObserver, observers_, OnAddVisit(this, info));
1247 void HistoryService::NotifyURLVisited(ui::PageTransition transition,
1248 const history::URLRow& row,
1249 const history::RedirectList& redirects,
1250 base::Time visit_time) {
1251 DCHECK(thread_checker_.CalledOnValidThread());
1252 FOR_EACH_OBSERVER(history::HistoryServiceObserver,
1254 OnURLVisited(this, transition, row, redirects, visit_time));
1257 scoped_ptr<base::CallbackList<void(const std::set<GURL>&)>::Subscription>
1258 HistoryService::AddFaviconChangedCallback(
1259 const HistoryService::OnFaviconChangedCallback& callback) {
1260 DCHECK(thread_checker_.CalledOnValidThread());
1261 return favicon_changed_callback_list_.Add(callback);
1264 void HistoryService::NotifyFaviconChanged(
1265 const std::set<GURL>& changed_favicons) {
1266 DCHECK(thread_checker_.CalledOnValidThread());
1267 favicon_changed_callback_list_.Notify(changed_favicons);