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/history_types.h"
39 #include "chrome/browser/history/in_memory_history_backend.h"
40 #include "chrome/browser/history/in_memory_url_index.h"
41 #include "chrome/browser/history/top_sites.h"
42 #include "chrome/browser/history/visit_database.h"
43 #include "chrome/browser/history/visit_filter.h"
44 #include "chrome/browser/history/web_history_service.h"
45 #include "chrome/browser/history/web_history_service_factory.h"
46 #include "chrome/browser/profiles/profile.h"
47 #include "chrome/common/chrome_constants.h"
48 #include "chrome/common/chrome_switches.h"
49 #include "chrome/common/importer/imported_favicon_usage.h"
50 #include "chrome/common/pref_names.h"
51 #include "chrome/common/url_constants.h"
52 #include "components/dom_distiller/core/url_constants.h"
53 #include "components/history/core/browser/history_client.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 BroadcastNotifications(
163 scoped_ptr<history::HistoryDetails> details) OVERRIDE {
164 // Send the notification on the history thread.
165 if (content::NotificationService::current()) {
166 content::Details<history::HistoryDetails> det(details.get());
167 content::NotificationService::current()->Notify(
168 type, content::Source<Profile>(profile_), det);
170 // Send the notification to the history service on the main thread.
171 service_task_runner_->PostTask(
173 base::Bind(&HistoryService::BroadcastNotificationsHelper,
174 history_service_, type, base::Passed(&details)));
177 virtual void DBLoaded() OVERRIDE {
178 service_task_runner_->PostTask(
180 base::Bind(&HistoryService::OnDBLoaded, history_service_));
183 virtual void NotifyVisitDBObserversOnAddVisit(
184 const history::BriefVisitInfo& info) OVERRIDE {
185 service_task_runner_->PostTask(
187 base::Bind(&HistoryService::NotifyVisitDBObserversOnAddVisit,
188 history_service_, info));
192 const base::WeakPtr<HistoryService> history_service_;
193 const scoped_refptr<base::SequencedTaskRunner> service_task_runner_;
194 Profile* const profile_;
197 // The history thread is intentionally not a BrowserThread because the
198 // sync integration unit tests depend on being able to create more than one
200 HistoryService::HistoryService()
201 : weak_ptr_factory_(this),
202 thread_(new base::Thread(kHistoryThreadName)),
203 history_client_(NULL),
205 backend_loaded_(false),
209 HistoryService::HistoryService(history::HistoryClient* client, Profile* profile)
210 : weak_ptr_factory_(this),
211 thread_(new base::Thread(kHistoryThreadName)),
212 history_client_(client),
214 visitedlink_master_(new visitedlink::VisitedLinkMaster(
215 profile, this, true)),
216 backend_loaded_(false),
219 registrar_.Add(this, chrome::NOTIFICATION_HISTORY_URLS_DELETED,
220 content::Source<Profile>(profile_));
223 HistoryService::~HistoryService() {
224 DCHECK(thread_checker_.CalledOnValidThread());
225 // Shutdown the backend. This does nothing if Cleanup was already invoked.
229 bool HistoryService::BackendLoaded() {
230 DCHECK(thread_checker_.CalledOnValidThread());
231 return backend_loaded_;
234 void HistoryService::Cleanup() {
235 DCHECK(thread_checker_.CalledOnValidThread());
237 // We've already cleaned up.
241 weak_ptr_factory_.InvalidateWeakPtrs();
243 // Unload the backend.
244 if (history_backend_) {
245 // Get rid of the in-memory backend.
246 in_memory_backend_.reset();
248 // Give the InMemoryURLIndex a chance to shutdown.
249 // NOTE: In tests, there may be no index.
250 if (in_memory_url_index_)
251 in_memory_url_index_->ShutDown();
253 // The backend's destructor must run on the history thread since it is not
254 // threadsafe. So this thread must not be the last thread holding a
255 // reference to the backend, or a crash could happen.
257 // We have a reference to the history backend. There is also an extra
258 // reference held by our delegate installed in the backend, which
259 // HistoryBackend::Closing will release. This means if we scheduled a call
260 // to HistoryBackend::Closing and *then* released our backend reference,
261 // there will be a race between us and the backend's Closing function to see
262 // who is the last holder of a reference. If the backend thread's Closing
263 // manages to run before we release our backend refptr, the last reference
264 // will be held by this thread and the destructor will be called from here.
266 // Therefore, we create a closure to run the Closing operation first. This
267 // holds a reference to the backend. Then we release our reference, then we
268 // schedule the task to run. After the task runs, it will delete its
269 // reference from the history thread, ensuring everything works properly.
271 // TODO(ajwong): Cleanup HistoryBackend lifetime issues.
272 // See http://crbug.com/99767.
273 history_backend_->AddRef();
274 base::Closure closing_task =
275 base::Bind(&HistoryBackend::Closing, history_backend_.get());
276 ScheduleTask(PRIORITY_NORMAL, closing_task);
277 closing_task.Reset();
278 HistoryBackend* raw_ptr = history_backend_.get();
279 history_backend_ = NULL;
280 thread_->message_loop()->ReleaseSoon(FROM_HERE, raw_ptr);
283 // Delete the thread, which joins with the background thread. We defensively
284 // NULL the pointer before deleting it in case somebody tries to use it
285 // during shutdown, but this shouldn't happen.
286 base::Thread* thread = thread_;
291 void HistoryService::ClearCachedDataForContextID(
292 history::ContextID context_id) {
293 DCHECK(thread_) << "History service being called after cleanup";
294 DCHECK(thread_checker_.CalledOnValidThread());
295 ScheduleAndForget(PRIORITY_NORMAL,
296 &HistoryBackend::ClearCachedDataForContextID, context_id);
299 history::URLDatabase* HistoryService::InMemoryDatabase() {
300 DCHECK(thread_checker_.CalledOnValidThread());
301 return in_memory_backend_ ? in_memory_backend_->db() : NULL;
304 bool HistoryService::GetTypedCountForURL(const GURL& url, int* typed_count) {
305 DCHECK(thread_checker_.CalledOnValidThread());
306 history::URLRow url_row;
307 if (!GetRowForURL(url, &url_row))
309 *typed_count = url_row.typed_count();
313 bool HistoryService::GetLastVisitTimeForURL(const GURL& url,
314 base::Time* last_visit) {
315 DCHECK(thread_checker_.CalledOnValidThread());
316 history::URLRow url_row;
317 if (!GetRowForURL(url, &url_row))
319 *last_visit = url_row.last_visit();
323 bool HistoryService::GetVisitCountForURL(const GURL& url, int* visit_count) {
324 DCHECK(thread_checker_.CalledOnValidThread());
325 history::URLRow url_row;
326 if (!GetRowForURL(url, &url_row))
328 *visit_count = url_row.visit_count();
332 history::TypedUrlSyncableService* HistoryService::GetTypedUrlSyncableService()
334 return history_backend_->GetTypedUrlSyncableService();
337 void HistoryService::Shutdown() {
338 DCHECK(thread_checker_.CalledOnValidThread());
342 void HistoryService::SetKeywordSearchTermsForURL(const GURL& url,
343 KeywordID keyword_id,
344 const base::string16& term) {
345 DCHECK(thread_) << "History service being called after cleanup";
346 DCHECK(thread_checker_.CalledOnValidThread());
347 ScheduleAndForget(PRIORITY_UI,
348 &HistoryBackend::SetKeywordSearchTermsForURL,
349 url, keyword_id, term);
352 void HistoryService::DeleteAllSearchTermsForKeyword(KeywordID keyword_id) {
353 DCHECK(thread_) << "History service being called after cleanup";
354 DCHECK(thread_checker_.CalledOnValidThread());
356 if (in_memory_backend_)
357 in_memory_backend_->DeleteAllSearchTermsForKeyword(keyword_id);
359 ScheduleAndForget(PRIORITY_UI,
360 &HistoryBackend::DeleteAllSearchTermsForKeyword,
364 void HistoryService::DeleteKeywordSearchTermForURL(const GURL& url) {
365 DCHECK(thread_) << "History service being called after cleanup";
366 DCHECK(thread_checker_.CalledOnValidThread());
367 ScheduleAndForget(PRIORITY_UI, &HistoryBackend::DeleteKeywordSearchTermForURL,
371 void HistoryService::DeleteMatchingURLsForKeyword(KeywordID keyword_id,
372 const base::string16& term) {
373 DCHECK(thread_) << "History service being called after cleanup";
374 DCHECK(thread_checker_.CalledOnValidThread());
375 ScheduleAndForget(PRIORITY_UI, &HistoryBackend::DeleteMatchingURLsForKeyword,
379 void HistoryService::URLsNoLongerBookmarked(const std::set<GURL>& urls) {
380 DCHECK(thread_) << "History service being called after cleanup";
381 DCHECK(thread_checker_.CalledOnValidThread());
382 ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::URLsNoLongerBookmarked,
386 void HistoryService::ScheduleDBTask(scoped_ptr<history::HistoryDBTask> task,
387 base::CancelableTaskTracker* tracker) {
388 DCHECK(thread_) << "History service being called after cleanup";
389 DCHECK(thread_checker_.CalledOnValidThread());
390 base::CancelableTaskTracker::IsCanceledCallback is_canceled;
391 tracker->NewTrackedTaskId(&is_canceled);
392 // Use base::ThreadTaskRunnerHandler::Get() to get a message loop proxy to
393 // the current message loop so that we can forward the call to the method
394 // HistoryDBTask::DoneRunOnMainThread in the correct thread.
395 thread_->message_loop_proxy()->PostTask(
397 base::Bind(&HistoryBackend::ProcessDBTask,
398 history_backend_.get(),
400 base::ThreadTaskRunnerHandle::Get(),
404 void HistoryService::FlushForTest(const base::Closure& flushed) {
405 thread_->message_loop_proxy()->PostTaskAndReply(
406 FROM_HERE, base::Bind(&base::DoNothing), flushed);
409 void HistoryService::SetOnBackendDestroyTask(const base::Closure& task) {
410 DCHECK(thread_) << "History service being called after cleanup";
411 DCHECK(thread_checker_.CalledOnValidThread());
412 ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::SetOnBackendDestroyTask,
413 base::MessageLoop::current(), task);
416 void HistoryService::AddPage(const GURL& url,
418 history::ContextID context_id,
420 const GURL& referrer,
421 const history::RedirectList& redirects,
422 content::PageTransition transition,
423 history::VisitSource visit_source,
424 bool did_replace_entry) {
425 DCHECK(thread_checker_.CalledOnValidThread());
427 history::HistoryAddPageArgs(url, time, context_id, page_id, referrer,
428 redirects, transition, visit_source,
432 void HistoryService::AddPage(const GURL& url,
434 history::VisitSource visit_source) {
435 DCHECK(thread_checker_.CalledOnValidThread());
437 history::HistoryAddPageArgs(url, time, NULL, 0, GURL(),
438 history::RedirectList(),
439 content::PAGE_TRANSITION_LINK,
440 visit_source, false));
443 void HistoryService::AddPage(const history::HistoryAddPageArgs& add_page_args) {
444 DCHECK(thread_) << "History service being called after cleanup";
445 DCHECK(thread_checker_.CalledOnValidThread());
447 // Filter out unwanted URLs. We don't add auto-subframe URLs. They are a
448 // large part of history (think iframes for ads) and we never display them in
449 // history UI. We will still add manual subframes, which are ones the user
450 // has clicked on to get.
451 if (!CanAddURL(add_page_args.url))
454 // Add link & all redirects to visited link list.
455 if (visitedlink_master_) {
456 visitedlink_master_->AddURL(add_page_args.url);
458 if (!add_page_args.redirects.empty()) {
459 // We should not be asked to add a page in the middle of a redirect chain.
460 DCHECK_EQ(add_page_args.url,
461 add_page_args.redirects[add_page_args.redirects.size() - 1]);
463 // We need the !redirects.empty() condition above since size_t is unsigned
464 // and will wrap around when we subtract one from a 0 size.
465 for (size_t i = 0; i < add_page_args.redirects.size() - 1; i++)
466 visitedlink_master_->AddURL(add_page_args.redirects[i]);
470 ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::AddPage, add_page_args);
473 void HistoryService::AddPageNoVisitForBookmark(const GURL& url,
474 const base::string16& title) {
475 DCHECK(thread_) << "History service being called after cleanup";
476 DCHECK(thread_checker_.CalledOnValidThread());
480 ScheduleAndForget(PRIORITY_NORMAL,
481 &HistoryBackend::AddPageNoVisitForBookmark, url, title);
484 void HistoryService::SetPageTitle(const GURL& url,
485 const base::string16& title) {
486 DCHECK(thread_) << "History service being called after cleanup";
487 DCHECK(thread_checker_.CalledOnValidThread());
488 ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::SetPageTitle, url, title);
491 void HistoryService::UpdateWithPageEndTime(history::ContextID context_id,
495 DCHECK(thread_) << "History service being called after cleanup";
496 DCHECK(thread_checker_.CalledOnValidThread());
497 ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::UpdateWithPageEndTime,
498 context_id, page_id, url, end_ts);
501 void HistoryService::AddPageWithDetails(const GURL& url,
502 const base::string16& title,
507 history::VisitSource visit_source) {
508 DCHECK(thread_) << "History service being called after cleanup";
509 DCHECK(thread_checker_.CalledOnValidThread());
510 // Filter out unwanted URLs.
514 // Add to the visited links system.
515 if (visitedlink_master_)
516 visitedlink_master_->AddURL(url);
518 history::URLRow row(url);
519 row.set_title(title);
520 row.set_visit_count(visit_count);
521 row.set_typed_count(typed_count);
522 row.set_last_visit(last_visit);
523 row.set_hidden(hidden);
525 history::URLRows rows;
528 ScheduleAndForget(PRIORITY_NORMAL,
529 &HistoryBackend::AddPagesWithDetails, rows, visit_source);
532 void HistoryService::AddPagesWithDetails(const history::URLRows& info,
533 history::VisitSource visit_source) {
534 DCHECK(thread_) << "History service being called after cleanup";
535 DCHECK(thread_checker_.CalledOnValidThread());
536 // Add to the visited links system.
537 if (visitedlink_master_) {
538 std::vector<GURL> urls;
539 urls.reserve(info.size());
540 for (history::URLRows::const_iterator i = info.begin(); i != info.end();
542 urls.push_back(i->url());
544 visitedlink_master_->AddURLs(urls);
547 ScheduleAndForget(PRIORITY_NORMAL,
548 &HistoryBackend::AddPagesWithDetails, info, visit_source);
551 base::CancelableTaskTracker::TaskId HistoryService::GetFavicons(
552 const std::vector<GURL>& icon_urls,
554 const std::vector<int>& desired_sizes,
555 const favicon_base::FaviconResultsCallback& callback,
556 base::CancelableTaskTracker* tracker) {
557 DCHECK(thread_) << "History service being called after cleanup";
558 DCHECK(thread_checker_.CalledOnValidThread());
559 std::vector<favicon_base::FaviconRawBitmapResult>* results =
560 new std::vector<favicon_base::FaviconRawBitmapResult>();
561 return tracker->PostTaskAndReply(
562 thread_->message_loop_proxy().get(),
564 base::Bind(&HistoryBackend::GetFavicons,
565 history_backend_.get(),
570 base::Bind(&RunWithFaviconResults, callback, base::Owned(results)));
573 base::CancelableTaskTracker::TaskId HistoryService::GetFaviconsForURL(
574 const GURL& page_url,
576 const std::vector<int>& desired_sizes,
577 const favicon_base::FaviconResultsCallback& callback,
578 base::CancelableTaskTracker* tracker) {
579 DCHECK(thread_) << "History service being called after cleanup";
580 DCHECK(thread_checker_.CalledOnValidThread());
581 std::vector<favicon_base::FaviconRawBitmapResult>* results =
582 new std::vector<favicon_base::FaviconRawBitmapResult>();
583 return tracker->PostTaskAndReply(
584 thread_->message_loop_proxy().get(),
586 base::Bind(&HistoryBackend::GetFaviconsForURL,
587 history_backend_.get(),
592 base::Bind(&RunWithFaviconResults, callback, base::Owned(results)));
595 base::CancelableTaskTracker::TaskId HistoryService::GetLargestFaviconForURL(
596 const GURL& page_url,
597 const std::vector<int>& icon_types,
598 int minimum_size_in_pixels,
599 const favicon_base::FaviconRawBitmapCallback& callback,
600 base::CancelableTaskTracker* tracker) {
601 DCHECK(thread_) << "History service being called after cleanup";
602 DCHECK(thread_checker_.CalledOnValidThread());
603 favicon_base::FaviconRawBitmapResult* result =
604 new favicon_base::FaviconRawBitmapResult();
605 return tracker->PostTaskAndReply(
606 thread_->message_loop_proxy().get(),
608 base::Bind(&HistoryBackend::GetLargestFaviconForURL,
609 history_backend_.get(),
612 minimum_size_in_pixels,
614 base::Bind(&RunWithFaviconResult, callback, base::Owned(result)));
617 base::CancelableTaskTracker::TaskId HistoryService::GetFaviconForID(
618 favicon_base::FaviconID favicon_id,
620 const favicon_base::FaviconResultsCallback& callback,
621 base::CancelableTaskTracker* tracker) {
622 DCHECK(thread_) << "History service being called after cleanup";
623 DCHECK(thread_checker_.CalledOnValidThread());
624 std::vector<favicon_base::FaviconRawBitmapResult>* results =
625 new std::vector<favicon_base::FaviconRawBitmapResult>();
626 return tracker->PostTaskAndReply(
627 thread_->message_loop_proxy().get(),
629 base::Bind(&HistoryBackend::GetFaviconForID,
630 history_backend_.get(),
634 base::Bind(&RunWithFaviconResults, callback, base::Owned(results)));
637 base::CancelableTaskTracker::TaskId
638 HistoryService::UpdateFaviconMappingsAndFetch(
639 const GURL& page_url,
640 const std::vector<GURL>& icon_urls,
642 const std::vector<int>& desired_sizes,
643 const favicon_base::FaviconResultsCallback& callback,
644 base::CancelableTaskTracker* tracker) {
645 DCHECK(thread_) << "History service being called after cleanup";
646 DCHECK(thread_checker_.CalledOnValidThread());
647 std::vector<favicon_base::FaviconRawBitmapResult>* results =
648 new std::vector<favicon_base::FaviconRawBitmapResult>();
649 return tracker->PostTaskAndReply(
650 thread_->message_loop_proxy().get(),
652 base::Bind(&HistoryBackend::UpdateFaviconMappingsAndFetch,
653 history_backend_.get(),
659 base::Bind(&RunWithFaviconResults, callback, base::Owned(results)));
662 void HistoryService::MergeFavicon(
663 const GURL& page_url,
664 const GURL& icon_url,
665 favicon_base::IconType icon_type,
666 scoped_refptr<base::RefCountedMemory> bitmap_data,
667 const gfx::Size& pixel_size) {
668 DCHECK(thread_) << "History service being called after cleanup";
669 DCHECK(thread_checker_.CalledOnValidThread());
670 if (!CanAddURL(page_url))
673 ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::MergeFavicon, page_url,
674 icon_url, icon_type, bitmap_data, pixel_size);
677 void HistoryService::SetFavicons(
678 const GURL& page_url,
679 favicon_base::IconType icon_type,
680 const std::vector<favicon_base::FaviconRawBitmapData>&
681 favicon_bitmap_data) {
682 DCHECK(thread_) << "History service being called after cleanup";
683 DCHECK(thread_checker_.CalledOnValidThread());
684 if (!CanAddURL(page_url))
687 ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::SetFavicons, page_url,
688 icon_type, favicon_bitmap_data);
691 void HistoryService::SetFaviconsOutOfDateForPage(const GURL& page_url) {
692 DCHECK(thread_) << "History service being called after cleanup";
693 DCHECK(thread_checker_.CalledOnValidThread());
694 ScheduleAndForget(PRIORITY_NORMAL,
695 &HistoryBackend::SetFaviconsOutOfDateForPage, page_url);
698 void HistoryService::CloneFavicons(const GURL& old_page_url,
699 const GURL& new_page_url) {
700 DCHECK(thread_) << "History service being called after cleanup";
701 DCHECK(thread_checker_.CalledOnValidThread());
702 ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::CloneFavicons,
703 old_page_url, new_page_url);
706 void HistoryService::SetImportedFavicons(
707 const std::vector<ImportedFaviconUsage>& favicon_usage) {
708 DCHECK(thread_) << "History service being called after cleanup";
709 DCHECK(thread_checker_.CalledOnValidThread());
710 ScheduleAndForget(PRIORITY_NORMAL,
711 &HistoryBackend::SetImportedFavicons, favicon_usage);
714 base::CancelableTaskTracker::TaskId HistoryService::QueryURL(
717 const QueryURLCallback& callback,
718 base::CancelableTaskTracker* tracker) {
719 DCHECK(thread_) << "History service being called after cleanup";
720 DCHECK(thread_checker_.CalledOnValidThread());
721 history::QueryURLResult* query_url_result = new history::QueryURLResult();
722 return tracker->PostTaskAndReply(
723 thread_->message_loop_proxy().get(),
725 base::Bind(&HistoryBackend::QueryURL,
726 history_backend_.get(),
729 base::Unretained(query_url_result)),
731 &RunWithQueryURLResult, callback, base::Owned(query_url_result)));
734 // Downloads -------------------------------------------------------------------
736 // Handle creation of a download by creating an entry in the history service's
737 // 'downloads' table.
738 void HistoryService::CreateDownload(
739 const history::DownloadRow& create_info,
740 const HistoryService::DownloadCreateCallback& callback) {
741 DCHECK(thread_) << "History service being called after cleanup";
742 DCHECK(thread_checker_.CalledOnValidThread());
743 PostTaskAndReplyWithResult(
744 thread_->message_loop_proxy(), FROM_HERE,
745 base::Bind(&HistoryBackend::CreateDownload, history_backend_.get(),
750 void HistoryService::GetNextDownloadId(
751 const content::DownloadIdCallback& callback) {
752 DCHECK(thread_) << "History service being called after cleanup";
753 DCHECK(thread_checker_.CalledOnValidThread());
754 PostTaskAndReplyWithResult(
755 thread_->message_loop_proxy(), FROM_HERE,
756 base::Bind(&HistoryBackend::GetNextDownloadId, history_backend_.get()),
760 // Handle queries for a list of all downloads in the history database's
761 // 'downloads' table.
762 void HistoryService::QueryDownloads(
763 const DownloadQueryCallback& callback) {
764 DCHECK(thread_) << "History service being called after cleanup";
765 DCHECK(thread_checker_.CalledOnValidThread());
766 std::vector<history::DownloadRow>* rows =
767 new std::vector<history::DownloadRow>();
768 scoped_ptr<std::vector<history::DownloadRow> > scoped_rows(rows);
769 // Beware! The first Bind() does not simply |scoped_rows.get()| because
770 // base::Passed(&scoped_rows) nullifies |scoped_rows|, and compilers do not
771 // guarantee that the first Bind's arguments are evaluated before the second
773 thread_->message_loop_proxy()->PostTaskAndReply(
775 base::Bind(&HistoryBackend::QueryDownloads, history_backend_.get(), rows),
776 base::Bind(callback, base::Passed(&scoped_rows)));
779 // Handle updates for a particular download. This is a 'fire and forget'
780 // operation, so we don't need to be called back.
781 void HistoryService::UpdateDownload(const history::DownloadRow& data) {
782 DCHECK(thread_) << "History service being called after cleanup";
783 DCHECK(thread_checker_.CalledOnValidThread());
784 ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::UpdateDownload, data);
787 void HistoryService::RemoveDownloads(const std::set<uint32>& ids) {
788 DCHECK(thread_) << "History service being called after cleanup";
789 DCHECK(thread_checker_.CalledOnValidThread());
790 ScheduleAndForget(PRIORITY_NORMAL,
791 &HistoryBackend::RemoveDownloads, ids);
794 base::CancelableTaskTracker::TaskId HistoryService::QueryHistory(
795 const base::string16& text_query,
796 const history::QueryOptions& options,
797 const QueryHistoryCallback& callback,
798 base::CancelableTaskTracker* tracker) {
799 DCHECK(thread_) << "History service being called after cleanup";
800 DCHECK(thread_checker_.CalledOnValidThread());
801 history::QueryResults* query_results = new history::QueryResults();
802 return tracker->PostTaskAndReply(
803 thread_->message_loop_proxy().get(),
805 base::Bind(&HistoryBackend::QueryHistory,
806 history_backend_.get(),
809 base::Unretained(query_results)),
810 base::Bind(callback, base::Owned(query_results)));
813 base::CancelableTaskTracker::TaskId HistoryService::QueryRedirectsFrom(
814 const GURL& from_url,
815 const QueryRedirectsCallback& callback,
816 base::CancelableTaskTracker* tracker) {
817 DCHECK(thread_) << "History service being called after cleanup";
818 DCHECK(thread_checker_.CalledOnValidThread());
819 history::RedirectList* result = new history::RedirectList();
820 return tracker->PostTaskAndReply(
821 thread_->message_loop_proxy().get(),
823 base::Bind(&HistoryBackend::QueryRedirectsFrom,
824 history_backend_.get(),
826 base::Unretained(result)),
827 base::Bind(callback, base::Owned(result)));
830 base::CancelableTaskTracker::TaskId HistoryService::QueryRedirectsTo(
832 const QueryRedirectsCallback& callback,
833 base::CancelableTaskTracker* tracker) {
834 DCHECK(thread_) << "History service being called after cleanup";
835 DCHECK(thread_checker_.CalledOnValidThread());
836 history::RedirectList* result = new history::RedirectList();
837 return tracker->PostTaskAndReply(thread_->message_loop_proxy().get(),
839 base::Bind(&HistoryBackend::QueryRedirectsTo,
840 history_backend_.get(),
842 base::Unretained(result)),
843 base::Bind(callback, base::Owned(result)));
846 base::CancelableTaskTracker::TaskId HistoryService::GetVisibleVisitCountToHost(
848 const GetVisibleVisitCountToHostCallback& callback,
849 base::CancelableTaskTracker* tracker) {
850 DCHECK(thread_) << "History service being called after cleanup";
851 DCHECK(thread_checker_.CalledOnValidThread());
852 history::VisibleVisitCountToHostResult* result =
853 new history::VisibleVisitCountToHostResult();
854 return tracker->PostTaskAndReply(
855 thread_->message_loop_proxy().get(),
857 base::Bind(&HistoryBackend::GetVisibleVisitCountToHost,
858 history_backend_.get(),
860 base::Unretained(result)),
861 base::Bind(&RunWithVisibleVisitCountToHostResult,
863 base::Owned(result)));
866 base::CancelableTaskTracker::TaskId HistoryService::QueryMostVisitedURLs(
869 const QueryMostVisitedURLsCallback& callback,
870 base::CancelableTaskTracker* tracker) {
871 DCHECK(thread_) << "History service being called after cleanup";
872 DCHECK(thread_checker_.CalledOnValidThread());
873 history::MostVisitedURLList* result = new history::MostVisitedURLList();
874 return tracker->PostTaskAndReply(
875 thread_->message_loop_proxy().get(),
877 base::Bind(&HistoryBackend::QueryMostVisitedURLs,
878 history_backend_.get(),
881 base::Unretained(result)),
882 base::Bind(callback, base::Owned(result)));
885 base::CancelableTaskTracker::TaskId HistoryService::QueryFilteredURLs(
887 const history::VisitFilter& filter,
889 const QueryFilteredURLsCallback& callback,
890 base::CancelableTaskTracker* tracker) {
891 DCHECK(thread_) << "History service being called after cleanup";
892 DCHECK(thread_checker_.CalledOnValidThread());
893 history::FilteredURLList* result = new history::FilteredURLList();
894 return tracker->PostTaskAndReply(
895 thread_->message_loop_proxy().get(),
897 base::Bind(&HistoryBackend::QueryFilteredURLs,
898 history_backend_.get(),
902 base::Unretained(result)),
903 base::Bind(callback, base::Owned(result)));
906 void HistoryService::Observe(int type,
907 const content::NotificationSource& source,
908 const content::NotificationDetails& details) {
909 DCHECK(thread_checker_.CalledOnValidThread());
914 case chrome::NOTIFICATION_HISTORY_URLS_DELETED: {
915 // Update the visited link system for deleted URLs. We will update the
916 // visited link system for added URLs as soon as we get the add
917 // notification (we don't have to wait for the backend, which allows us to
918 // be faster to update the state).
920 // For deleted URLs, we don't typically know what will be deleted since
921 // delete notifications are by time. We would also like to be more
922 // respectful of privacy and never tell the user something is gone when it
923 // isn't. Therefore, we update the delete URLs after the fact.
924 if (visitedlink_master_) {
925 content::Details<history::URLsDeletedDetails> deleted_details(details);
927 if (deleted_details->all_history) {
928 visitedlink_master_->DeleteAllURLs();
930 URLIteratorFromURLRows iterator(deleted_details->rows);
931 visitedlink_master_->DeleteURLs(&iterator);
942 void HistoryService::RebuildTable(
943 const scoped_refptr<URLEnumerator>& enumerator) {
944 DCHECK(thread_) << "History service being called after cleanup";
945 DCHECK(thread_checker_.CalledOnValidThread());
946 ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::IterateURLs, enumerator);
949 bool HistoryService::Init(const base::FilePath& history_dir, bool no_db) {
950 DCHECK(thread_) << "History service being called after cleanup";
951 DCHECK(thread_checker_.CalledOnValidThread());
952 base::Thread::Options options;
953 options.timer_slack = base::TIMER_SLACK_MAXIMUM;
954 if (!thread_->StartWithOptions(options)) {
959 history_dir_ = history_dir;
963 std::string languages =
964 profile_->GetPrefs()->GetString(prefs::kAcceptLanguages);
965 in_memory_url_index_.reset(new history::InMemoryURLIndex(
966 profile_, history_dir_, languages, history_client_));
967 in_memory_url_index_->Init();
970 // Create the history backend.
971 scoped_refptr<HistoryBackend> backend(
972 new HistoryBackend(history_dir_,
974 weak_ptr_factory_.GetWeakPtr(),
975 base::ThreadTaskRunnerHandle::Get(),
978 history_backend_.swap(backend);
980 // There may not be a profile when unit testing.
981 std::string languages;
983 PrefService* prefs = profile_->GetPrefs();
984 languages = prefs->GetString(prefs::kAcceptLanguages);
986 ScheduleAndForget(PRIORITY_UI, &HistoryBackend::Init, languages, no_db_);
988 if (visitedlink_master_) {
989 bool result = visitedlink_master_->Init();
996 void HistoryService::ScheduleAutocomplete(const base::Callback<
997 void(history::HistoryBackend*, history::URLDatabase*)>& callback) {
998 DCHECK(thread_checker_.CalledOnValidThread());
1000 PRIORITY_UI, &HistoryBackend::ScheduleAutocomplete, callback);
1003 void HistoryService::ScheduleTask(SchedulePriority priority,
1004 const base::Closure& task) {
1005 DCHECK(thread_checker_.CalledOnValidThread());
1007 CHECK(thread_->message_loop());
1008 // TODO(brettw): Do prioritization.
1009 thread_->message_loop()->PostTask(FROM_HERE, task);
1013 bool HistoryService::CanAddURL(const GURL& url) {
1014 if (!url.is_valid())
1017 // TODO: We should allow kChromeUIScheme URLs if they have been explicitly
1018 // typed. Right now, however, these are marked as typed even when triggered
1019 // by a shortcut or menu action.
1020 if (url.SchemeIs(url::kJavaScriptScheme) ||
1021 url.SchemeIs(content::kChromeDevToolsScheme) ||
1022 url.SchemeIs(content::kChromeUIScheme) ||
1023 url.SchemeIs(content::kViewSourceScheme) ||
1024 url.SchemeIs(chrome::kChromeNativeScheme) ||
1025 url.SchemeIs(chrome::kChromeSearchScheme) ||
1026 url.SchemeIs(dom_distiller::kDomDistillerScheme))
1029 // Allow all about: and chrome: URLs except about:blank, since the user may
1030 // like to see "chrome://memory/", etc. in their history and autocomplete.
1031 if (url == GURL(url::kAboutBlankURL))
1037 base::WeakPtr<HistoryService> HistoryService::AsWeakPtr() {
1038 DCHECK(thread_checker_.CalledOnValidThread());
1039 return weak_ptr_factory_.GetWeakPtr();
1042 syncer::SyncMergeResult HistoryService::MergeDataAndStartSyncing(
1043 syncer::ModelType type,
1044 const syncer::SyncDataList& initial_sync_data,
1045 scoped_ptr<syncer::SyncChangeProcessor> sync_processor,
1046 scoped_ptr<syncer::SyncErrorFactory> error_handler) {
1047 DCHECK(thread_checker_.CalledOnValidThread());
1048 DCHECK_EQ(type, syncer::HISTORY_DELETE_DIRECTIVES);
1049 delete_directive_handler_.Start(this, initial_sync_data,
1050 sync_processor.Pass());
1051 return syncer::SyncMergeResult(type);
1054 void HistoryService::StopSyncing(syncer::ModelType type) {
1055 DCHECK(thread_checker_.CalledOnValidThread());
1056 DCHECK_EQ(type, syncer::HISTORY_DELETE_DIRECTIVES);
1057 delete_directive_handler_.Stop();
1060 syncer::SyncDataList HistoryService::GetAllSyncData(
1061 syncer::ModelType type) const {
1062 DCHECK(thread_checker_.CalledOnValidThread());
1063 DCHECK_EQ(type, syncer::HISTORY_DELETE_DIRECTIVES);
1064 // TODO(akalin): Keep track of existing delete directives.
1065 return syncer::SyncDataList();
1068 syncer::SyncError HistoryService::ProcessSyncChanges(
1069 const tracked_objects::Location& from_here,
1070 const syncer::SyncChangeList& change_list) {
1071 delete_directive_handler_.ProcessSyncChanges(this, change_list);
1072 return syncer::SyncError();
1075 syncer::SyncError HistoryService::ProcessLocalDeleteDirective(
1076 const sync_pb::HistoryDeleteDirectiveSpecifics& delete_directive) {
1077 DCHECK(thread_checker_.CalledOnValidThread());
1078 return delete_directive_handler_.ProcessLocalDeleteDirective(
1082 void HistoryService::SetInMemoryBackend(
1083 scoped_ptr<history::InMemoryHistoryBackend> mem_backend) {
1084 DCHECK(thread_checker_.CalledOnValidThread());
1085 DCHECK(!in_memory_backend_) << "Setting mem DB twice";
1086 in_memory_backend_.reset(mem_backend.release());
1088 // The database requires additional initialization once we own it.
1089 in_memory_backend_->AttachToHistoryService(profile_);
1092 void HistoryService::NotifyProfileError(sql::InitStatus init_status) {
1093 DCHECK(thread_checker_.CalledOnValidThread());
1094 if (history_client_)
1095 history_client_->NotifyProfileError(init_status);
1098 void HistoryService::DeleteURL(const GURL& url) {
1099 DCHECK(thread_) << "History service being called after cleanup";
1100 DCHECK(thread_checker_.CalledOnValidThread());
1101 // We will update the visited links when we observe the delete notifications.
1102 ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::DeleteURL, url);
1105 void HistoryService::DeleteURLsForTest(const std::vector<GURL>& urls) {
1106 DCHECK(thread_) << "History service being called after cleanup";
1107 DCHECK(thread_checker_.CalledOnValidThread());
1108 // We will update the visited links when we observe the delete
1110 ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::DeleteURLs, urls);
1113 void HistoryService::ExpireHistoryBetween(
1114 const std::set<GURL>& restrict_urls,
1117 const base::Closure& callback,
1118 base::CancelableTaskTracker* tracker) {
1119 DCHECK(thread_) << "History service being called after cleanup";
1120 DCHECK(thread_checker_.CalledOnValidThread());
1121 tracker->PostTaskAndReply(thread_->message_loop_proxy().get(),
1123 base::Bind(&HistoryBackend::ExpireHistoryBetween,
1131 void HistoryService::ExpireHistory(
1132 const std::vector<history::ExpireHistoryArgs>& expire_list,
1133 const base::Closure& callback,
1134 base::CancelableTaskTracker* tracker) {
1135 DCHECK(thread_) << "History service being called after cleanup";
1136 DCHECK(thread_checker_.CalledOnValidThread());
1137 tracker->PostTaskAndReply(
1138 thread_->message_loop_proxy().get(),
1140 base::Bind(&HistoryBackend::ExpireHistory, history_backend_, expire_list),
1144 void HistoryService::ExpireLocalAndRemoteHistoryBetween(
1145 const std::set<GURL>& restrict_urls,
1148 const base::Closure& callback,
1149 base::CancelableTaskTracker* tracker) {
1150 // TODO(dubroy): This should be factored out into a separate class that
1151 // dispatches deletions to the proper places.
1153 history::WebHistoryService* web_history =
1154 WebHistoryServiceFactory::GetForProfile(profile_);
1156 // TODO(dubroy): This API does not yet support deletion of specific URLs.
1157 DCHECK(restrict_urls.empty());
1159 delete_directive_handler_.CreateDeleteDirectives(
1160 std::set<int64>(), begin_time, end_time);
1162 // Attempt online deletion from the history server, but ignore the result.
1163 // Deletion directives ensure that the results will eventually be deleted.
1165 // TODO(davidben): |callback| should not run until this operation completes
1167 web_history->ExpireHistoryBetween(
1168 restrict_urls, begin_time, end_time,
1169 base::Bind(&ExpireWebHistoryComplete));
1171 ExpireHistoryBetween(restrict_urls, begin_time, end_time, callback, tracker);
1174 void HistoryService::BroadcastNotificationsHelper(
1176 scoped_ptr<history::HistoryDetails> details) {
1177 DCHECK(thread_checker_.CalledOnValidThread());
1178 // TODO(evanm): this is currently necessitated by generate_profile, which
1179 // runs without a browser process. generate_profile should really create
1180 // a browser process, at which point this check can then be nuked.
1181 if (!g_browser_process)
1187 // The source of all of our notifications is the profile. Note that this
1188 // pointer is NULL in unit tests.
1189 content::Source<Profile> source(profile_);
1191 // The details object just contains the pointer to the object that the
1192 // backend has allocated for us. The receiver of the notification will cast
1193 // this to the proper type.
1194 content::Details<history::HistoryDetails> det(details.get());
1196 content::NotificationService::current()->Notify(type, source, det);
1199 void HistoryService::OnDBLoaded() {
1200 DCHECK(thread_checker_.CalledOnValidThread());
1201 backend_loaded_ = true;
1202 content::NotificationService::current()->Notify(
1203 chrome::NOTIFICATION_HISTORY_LOADED,
1204 content::Source<Profile>(profile_),
1205 content::Details<HistoryService>(this));
1208 bool HistoryService::GetRowForURL(const GURL& url, history::URLRow* url_row) {
1209 DCHECK(thread_checker_.CalledOnValidThread());
1210 history::URLDatabase* db = InMemoryDatabase();
1211 return db && (db->GetRowForURL(url, url_row) != 0);
1214 void HistoryService::AddVisitDatabaseObserver(
1215 history::VisitDatabaseObserver* observer) {
1216 DCHECK(thread_checker_.CalledOnValidThread());
1217 visit_database_observers_.AddObserver(observer);
1220 void HistoryService::RemoveVisitDatabaseObserver(
1221 history::VisitDatabaseObserver* observer) {
1222 DCHECK(thread_checker_.CalledOnValidThread());
1223 visit_database_observers_.RemoveObserver(observer);
1226 void HistoryService::NotifyVisitDBObserversOnAddVisit(
1227 const history::BriefVisitInfo& info) {
1228 DCHECK(thread_checker_.CalledOnValidThread());
1229 FOR_EACH_OBSERVER(history::VisitDatabaseObserver, visit_database_observers_,