history_service.cc revision 116680a4aac90f2aa7413d9095a592090648e557
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.
4
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
8// that thread.
9//
10// Main thread                       History thread
11// -----------                       --------------
12// HistoryService <----------------> HistoryBackend
13//                                   -> HistoryDatabase
14//                                      -> SQLite connection to History
15//                                   -> ThumbnailDatabase
16//                                      -> SQLite connection to Thumbnails
17//                                         (and favicons)
18
19#include "chrome/browser/history/history_service.h"
20
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/history/core/browser/history_client.h"
53#include "components/history/core/browser/in_memory_database.h"
54#include "components/history/core/browser/keyword_search_term.h"
55#include "components/history/core/common/thumbnail_score.h"
56#include "components/visitedlink/browser/visitedlink_master.h"
57#include "content/public/browser/browser_thread.h"
58#include "content/public/browser/download_item.h"
59#include "content/public/browser/notification_service.h"
60#include "grit/chromium_strings.h"
61#include "grit/generated_resources.h"
62#include "sync/api/sync_error_factory.h"
63#include "third_party/skia/include/core/SkBitmap.h"
64
65using base::Time;
66using history::HistoryBackend;
67using history::KeywordID;
68
69namespace {
70
71static const char* kHistoryThreadName = "Chrome_HistoryThread";
72
73void RunWithFaviconResults(
74    const favicon_base::FaviconResultsCallback& callback,
75    std::vector<favicon_base::FaviconRawBitmapResult>* bitmap_results) {
76  callback.Run(*bitmap_results);
77}
78
79void RunWithFaviconResult(
80    const favicon_base::FaviconRawBitmapCallback& callback,
81    favicon_base::FaviconRawBitmapResult* bitmap_result) {
82  callback.Run(*bitmap_result);
83}
84
85void RunWithQueryURLResult(const HistoryService::QueryURLCallback& callback,
86                           const history::QueryURLResult* result) {
87  callback.Run(result->success, result->row, result->visits);
88}
89
90void RunWithVisibleVisitCountToHostResult(
91    const HistoryService::GetVisibleVisitCountToHostCallback& callback,
92    const history::VisibleVisitCountToHostResult* result) {
93  callback.Run(result->success, result->count, result->first_visit);
94}
95
96// Extract history::URLRows into GURLs for VisitedLinkMaster.
97class URLIteratorFromURLRows
98    : public visitedlink::VisitedLinkMaster::URLIterator {
99 public:
100  explicit URLIteratorFromURLRows(const history::URLRows& url_rows)
101      : itr_(url_rows.begin()),
102        end_(url_rows.end()) {
103  }
104
105  virtual const GURL& NextURL() OVERRIDE {
106    return (itr_++)->url();
107  }
108
109  virtual bool HasNextURL() const OVERRIDE {
110    return itr_ != end_;
111  }
112
113 private:
114  history::URLRows::const_iterator itr_;
115  history::URLRows::const_iterator end_;
116
117  DISALLOW_COPY_AND_ASSIGN(URLIteratorFromURLRows);
118};
119
120// Callback from WebHistoryService::ExpireWebHistory().
121void ExpireWebHistoryComplete(bool success) {
122  // Ignore the result.
123  //
124  // TODO(davidben): ExpireLocalAndRemoteHistoryBetween callback should not fire
125  // until this completes.
126}
127
128}  // namespace
129
130// Sends messages from the backend to us on the main thread. This must be a
131// separate class from the history service so that it can hold a reference to
132// the history service (otherwise we would have to manually AddRef and
133// Release when the Backend has a reference to us).
134class HistoryService::BackendDelegate : public HistoryBackend::Delegate {
135 public:
136  BackendDelegate(
137      const base::WeakPtr<HistoryService>& history_service,
138      const scoped_refptr<base::SequencedTaskRunner>& service_task_runner,
139      Profile* profile)
140      : history_service_(history_service),
141        service_task_runner_(service_task_runner),
142        profile_(profile) {
143  }
144
145  virtual void NotifyProfileError(sql::InitStatus init_status) OVERRIDE {
146    // Send to the history service on the main thread.
147    service_task_runner_->PostTask(
148        FROM_HERE,
149        base::Bind(&HistoryService::NotifyProfileError, history_service_,
150                   init_status));
151  }
152
153  virtual void SetInMemoryBackend(
154      scoped_ptr<history::InMemoryHistoryBackend> backend) OVERRIDE {
155    // Send the backend to the history service on the main thread.
156    service_task_runner_->PostTask(
157        FROM_HERE,
158        base::Bind(&HistoryService::SetInMemoryBackend, history_service_,
159                   base::Passed(&backend)));
160  }
161
162  virtual void BroadcastNotifications(
163      int type,
164      scoped_ptr<history::HistoryDetails> details) OVERRIDE {
165    // Send the notification on the history thread.
166    if (content::NotificationService::current()) {
167      content::Details<history::HistoryDetails> det(details.get());
168      content::NotificationService::current()->Notify(
169          type, content::Source<Profile>(profile_), det);
170    }
171    // Send the notification to the history service on the main thread.
172    service_task_runner_->PostTask(
173        FROM_HERE,
174        base::Bind(&HistoryService::BroadcastNotificationsHelper,
175                   history_service_, type, base::Passed(&details)));
176  }
177
178  virtual void DBLoaded() OVERRIDE {
179    service_task_runner_->PostTask(
180        FROM_HERE,
181        base::Bind(&HistoryService::OnDBLoaded, history_service_));
182  }
183
184  virtual void NotifyVisitDBObserversOnAddVisit(
185      const history::BriefVisitInfo& info) OVERRIDE {
186    service_task_runner_->PostTask(
187        FROM_HERE,
188        base::Bind(&HistoryService::NotifyVisitDBObserversOnAddVisit,
189                   history_service_, info));
190  }
191
192 private:
193  const base::WeakPtr<HistoryService> history_service_;
194  const scoped_refptr<base::SequencedTaskRunner> service_task_runner_;
195  Profile* const profile_;
196};
197
198// The history thread is intentionally not a BrowserThread because the
199// sync integration unit tests depend on being able to create more than one
200// history thread.
201HistoryService::HistoryService()
202    : weak_ptr_factory_(this),
203      thread_(new base::Thread(kHistoryThreadName)),
204      history_client_(NULL),
205      profile_(NULL),
206      backend_loaded_(false),
207      no_db_(false) {
208}
209
210HistoryService::HistoryService(history::HistoryClient* client, Profile* profile)
211    : weak_ptr_factory_(this),
212      thread_(new base::Thread(kHistoryThreadName)),
213      history_client_(client),
214      profile_(profile),
215      visitedlink_master_(new visitedlink::VisitedLinkMaster(
216          profile, this, true)),
217      backend_loaded_(false),
218      no_db_(false) {
219  DCHECK(profile_);
220  registrar_.Add(this, chrome::NOTIFICATION_HISTORY_URLS_DELETED,
221                 content::Source<Profile>(profile_));
222}
223
224HistoryService::~HistoryService() {
225  DCHECK(thread_checker_.CalledOnValidThread());
226  // Shutdown the backend. This does nothing if Cleanup was already invoked.
227  Cleanup();
228}
229
230bool HistoryService::BackendLoaded() {
231  DCHECK(thread_checker_.CalledOnValidThread());
232  return backend_loaded_;
233}
234
235void HistoryService::Cleanup() {
236  DCHECK(thread_checker_.CalledOnValidThread());
237  if (!thread_) {
238    // We've already cleaned up.
239    return;
240  }
241
242  weak_ptr_factory_.InvalidateWeakPtrs();
243
244  // Unload the backend.
245  if (history_backend_) {
246    // Get rid of the in-memory backend.
247    in_memory_backend_.reset();
248
249    // Give the InMemoryURLIndex a chance to shutdown.
250    // NOTE: In tests, there may be no index.
251    if (in_memory_url_index_)
252      in_memory_url_index_->ShutDown();
253
254    // The backend's destructor must run on the history thread since it is not
255    // threadsafe. So this thread must not be the last thread holding a
256    // reference to the backend, or a crash could happen.
257    //
258    // We have a reference to the history backend. There is also an extra
259    // reference held by our delegate installed in the backend, which
260    // HistoryBackend::Closing will release. This means if we scheduled a call
261    // to HistoryBackend::Closing and *then* released our backend reference,
262    // there will be a race between us and the backend's Closing function to see
263    // who is the last holder of a reference. If the backend thread's Closing
264    // manages to run before we release our backend refptr, the last reference
265    // will be held by this thread and the destructor will be called from here.
266    //
267    // Therefore, we create a closure to run the Closing operation first. This
268    // holds a reference to the backend. Then we release our reference, then we
269    // schedule the task to run. After the task runs, it will delete its
270    // reference from the history thread, ensuring everything works properly.
271    //
272    // TODO(ajwong): Cleanup HistoryBackend lifetime issues.
273    //     See http://crbug.com/99767.
274    history_backend_->AddRef();
275    base::Closure closing_task =
276        base::Bind(&HistoryBackend::Closing, history_backend_.get());
277    ScheduleTask(PRIORITY_NORMAL, closing_task);
278    closing_task.Reset();
279    HistoryBackend* raw_ptr = history_backend_.get();
280    history_backend_ = NULL;
281    thread_->message_loop()->ReleaseSoon(FROM_HERE, raw_ptr);
282  }
283
284  // Delete the thread, which joins with the background thread. We defensively
285  // NULL the pointer before deleting it in case somebody tries to use it
286  // during shutdown, but this shouldn't happen.
287  base::Thread* thread = thread_;
288  thread_ = NULL;
289  delete thread;
290}
291
292void HistoryService::ClearCachedDataForContextID(
293    history::ContextID context_id) {
294  DCHECK(thread_checker_.CalledOnValidThread());
295  ScheduleAndForget(PRIORITY_NORMAL,
296                    &HistoryBackend::ClearCachedDataForContextID, context_id);
297}
298
299history::URLDatabase* HistoryService::InMemoryDatabase() {
300  DCHECK(thread_checker_.CalledOnValidThread());
301  return in_memory_backend_ ? in_memory_backend_->db() : NULL;
302}
303
304bool HistoryService::GetTypedCountForURL(const GURL& url, int* typed_count) {
305  DCHECK(thread_checker_.CalledOnValidThread());
306  history::URLRow url_row;
307  if (!GetRowForURL(url, &url_row))
308    return false;
309  *typed_count = url_row.typed_count();
310  return true;
311}
312
313bool 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))
318    return false;
319  *last_visit = url_row.last_visit();
320  return true;
321}
322
323bool HistoryService::GetVisitCountForURL(const GURL& url, int* visit_count) {
324  DCHECK(thread_checker_.CalledOnValidThread());
325  history::URLRow url_row;
326  if (!GetRowForURL(url, &url_row))
327    return false;
328  *visit_count = url_row.visit_count();
329  return true;
330}
331
332history::TypedUrlSyncableService* HistoryService::GetTypedUrlSyncableService()
333    const {
334  return history_backend_->GetTypedUrlSyncableService();
335}
336
337void HistoryService::Shutdown() {
338  DCHECK(thread_checker_.CalledOnValidThread());
339  Cleanup();
340}
341
342void HistoryService::SetKeywordSearchTermsForURL(const GURL& url,
343                                                 KeywordID keyword_id,
344                                                 const base::string16& term) {
345  DCHECK(thread_checker_.CalledOnValidThread());
346  ScheduleAndForget(PRIORITY_UI,
347                    &HistoryBackend::SetKeywordSearchTermsForURL,
348                    url, keyword_id, term);
349}
350
351void HistoryService::DeleteAllSearchTermsForKeyword(KeywordID keyword_id) {
352  DCHECK(thread_checker_.CalledOnValidThread());
353
354  if (in_memory_backend_)
355    in_memory_backend_->DeleteAllSearchTermsForKeyword(keyword_id);
356
357  ScheduleAndForget(PRIORITY_UI,
358                    &HistoryBackend::DeleteAllSearchTermsForKeyword,
359                    keyword_id);
360}
361
362void HistoryService::DeleteKeywordSearchTermForURL(const GURL& url) {
363  DCHECK(thread_checker_.CalledOnValidThread());
364  ScheduleAndForget(PRIORITY_UI, &HistoryBackend::DeleteKeywordSearchTermForURL,
365                    url);
366}
367
368void HistoryService::DeleteMatchingURLsForKeyword(KeywordID keyword_id,
369                                                  const base::string16& term) {
370  DCHECK(thread_checker_.CalledOnValidThread());
371  ScheduleAndForget(PRIORITY_UI, &HistoryBackend::DeleteMatchingURLsForKeyword,
372                    keyword_id, term);
373}
374
375void HistoryService::URLsNoLongerBookmarked(const std::set<GURL>& urls) {
376  DCHECK(thread_checker_.CalledOnValidThread());
377  ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::URLsNoLongerBookmarked,
378                    urls);
379}
380
381void HistoryService::ScheduleDBTask(scoped_refptr<history::HistoryDBTask> task,
382                                    base::CancelableTaskTracker* tracker) {
383  DCHECK(thread_checker_.CalledOnValidThread());
384  base::CancelableTaskTracker::IsCanceledCallback is_canceled;
385  tracker->NewTrackedTaskId(&is_canceled);
386  // Use base::ThreadTaskRunnerHandler::Get() to get a message loop proxy to
387  // the current message loop so that we can forward the call to the method
388  // HistoryDBTask::DoneRunOnMainThread in the correct thread.
389  thread_->message_loop_proxy()->PostTask(
390      FROM_HERE,
391      base::Bind(&HistoryBackend::ProcessDBTask,
392                 history_backend_.get(),
393                 task,
394                 base::ThreadTaskRunnerHandle::Get(),
395                 is_canceled));
396}
397
398void HistoryService::FlushForTest(const base::Closure& flushed) {
399  thread_->message_loop_proxy()->PostTaskAndReply(
400      FROM_HERE, base::Bind(&base::DoNothing), flushed);
401}
402
403void HistoryService::SetOnBackendDestroyTask(const base::Closure& task) {
404  DCHECK(thread_checker_.CalledOnValidThread());
405  ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::SetOnBackendDestroyTask,
406                    base::MessageLoop::current(), task);
407}
408
409void HistoryService::AddPage(const GURL& url,
410                             Time time,
411                             history::ContextID context_id,
412                             int32 page_id,
413                             const GURL& referrer,
414                             const history::RedirectList& redirects,
415                             content::PageTransition transition,
416                             history::VisitSource visit_source,
417                             bool did_replace_entry) {
418  DCHECK(thread_checker_.CalledOnValidThread());
419  AddPage(
420      history::HistoryAddPageArgs(url, time, context_id, page_id, referrer,
421                                  redirects, transition, visit_source,
422                                  did_replace_entry));
423}
424
425void HistoryService::AddPage(const GURL& url,
426                             base::Time time,
427                             history::VisitSource visit_source) {
428  DCHECK(thread_checker_.CalledOnValidThread());
429  AddPage(
430      history::HistoryAddPageArgs(url, time, NULL, 0, GURL(),
431                                  history::RedirectList(),
432                                  content::PAGE_TRANSITION_LINK,
433                                  visit_source, false));
434}
435
436void HistoryService::AddPage(const history::HistoryAddPageArgs& add_page_args) {
437  DCHECK(thread_checker_.CalledOnValidThread());
438  DCHECK(thread_) << "History service being called after cleanup";
439
440  // Filter out unwanted URLs. We don't add auto-subframe URLs. They are a
441  // large part of history (think iframes for ads) and we never display them in
442  // history UI. We will still add manual subframes, which are ones the user
443  // has clicked on to get.
444  if (!CanAddURL(add_page_args.url))
445    return;
446
447  // Add link & all redirects to visited link list.
448  if (visitedlink_master_) {
449    visitedlink_master_->AddURL(add_page_args.url);
450
451    if (!add_page_args.redirects.empty()) {
452      // We should not be asked to add a page in the middle of a redirect chain.
453      DCHECK_EQ(add_page_args.url,
454                add_page_args.redirects[add_page_args.redirects.size() - 1]);
455
456      // We need the !redirects.empty() condition above since size_t is unsigned
457      // and will wrap around when we subtract one from a 0 size.
458      for (size_t i = 0; i < add_page_args.redirects.size() - 1; i++)
459        visitedlink_master_->AddURL(add_page_args.redirects[i]);
460    }
461  }
462
463  ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::AddPage, add_page_args);
464}
465
466void HistoryService::AddPageNoVisitForBookmark(const GURL& url,
467                                               const base::string16& title) {
468  DCHECK(thread_checker_.CalledOnValidThread());
469  if (!CanAddURL(url))
470    return;
471
472  ScheduleAndForget(PRIORITY_NORMAL,
473                    &HistoryBackend::AddPageNoVisitForBookmark, url, title);
474}
475
476void HistoryService::SetPageTitle(const GURL& url,
477                                  const base::string16& title) {
478  DCHECK(thread_checker_.CalledOnValidThread());
479  ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::SetPageTitle, url, title);
480}
481
482void HistoryService::UpdateWithPageEndTime(history::ContextID context_id,
483                                           int32 page_id,
484                                           const GURL& url,
485                                           Time end_ts) {
486  DCHECK(thread_checker_.CalledOnValidThread());
487  ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::UpdateWithPageEndTime,
488                    context_id, page_id, url, end_ts);
489}
490
491void HistoryService::AddPageWithDetails(const GURL& url,
492                                        const base::string16& title,
493                                        int visit_count,
494                                        int typed_count,
495                                        Time last_visit,
496                                        bool hidden,
497                                        history::VisitSource visit_source) {
498  DCHECK(thread_checker_.CalledOnValidThread());
499  // Filter out unwanted URLs.
500  if (!CanAddURL(url))
501    return;
502
503  // Add to the visited links system.
504  if (visitedlink_master_)
505    visitedlink_master_->AddURL(url);
506
507  history::URLRow row(url);
508  row.set_title(title);
509  row.set_visit_count(visit_count);
510  row.set_typed_count(typed_count);
511  row.set_last_visit(last_visit);
512  row.set_hidden(hidden);
513
514  history::URLRows rows;
515  rows.push_back(row);
516
517  ScheduleAndForget(PRIORITY_NORMAL,
518                    &HistoryBackend::AddPagesWithDetails, rows, visit_source);
519}
520
521void HistoryService::AddPagesWithDetails(const history::URLRows& info,
522                                         history::VisitSource visit_source) {
523  DCHECK(thread_checker_.CalledOnValidThread());
524  // Add to the visited links system.
525  if (visitedlink_master_) {
526    std::vector<GURL> urls;
527    urls.reserve(info.size());
528    for (history::URLRows::const_iterator i = info.begin(); i != info.end();
529         ++i)
530      urls.push_back(i->url());
531
532    visitedlink_master_->AddURLs(urls);
533  }
534
535  ScheduleAndForget(PRIORITY_NORMAL,
536                    &HistoryBackend::AddPagesWithDetails, info, visit_source);
537}
538
539base::CancelableTaskTracker::TaskId HistoryService::GetFavicons(
540    const std::vector<GURL>& icon_urls,
541    int icon_types,
542    const std::vector<int>& desired_sizes,
543    const favicon_base::FaviconResultsCallback& callback,
544    base::CancelableTaskTracker* tracker) {
545  DCHECK(thread_checker_.CalledOnValidThread());
546
547  std::vector<favicon_base::FaviconRawBitmapResult>* results =
548      new std::vector<favicon_base::FaviconRawBitmapResult>();
549  return tracker->PostTaskAndReply(
550      thread_->message_loop_proxy().get(),
551      FROM_HERE,
552      base::Bind(&HistoryBackend::GetFavicons,
553                 history_backend_.get(),
554                 icon_urls,
555                 icon_types,
556                 desired_sizes,
557                 results),
558      base::Bind(&RunWithFaviconResults, callback, base::Owned(results)));
559}
560
561base::CancelableTaskTracker::TaskId HistoryService::GetFaviconsForURL(
562    const GURL& page_url,
563    int icon_types,
564    const std::vector<int>& desired_sizes,
565    const favicon_base::FaviconResultsCallback& callback,
566    base::CancelableTaskTracker* tracker) {
567  DCHECK(thread_checker_.CalledOnValidThread());
568
569  std::vector<favicon_base::FaviconRawBitmapResult>* results =
570      new std::vector<favicon_base::FaviconRawBitmapResult>();
571  return tracker->PostTaskAndReply(
572      thread_->message_loop_proxy().get(),
573      FROM_HERE,
574      base::Bind(&HistoryBackend::GetFaviconsForURL,
575                 history_backend_.get(),
576                 page_url,
577                 icon_types,
578                 desired_sizes,
579                 results),
580      base::Bind(&RunWithFaviconResults, callback, base::Owned(results)));
581}
582
583base::CancelableTaskTracker::TaskId HistoryService::GetLargestFaviconForURL(
584    const GURL& page_url,
585    const std::vector<int>& icon_types,
586    int minimum_size_in_pixels,
587    const favicon_base::FaviconRawBitmapCallback& callback,
588    base::CancelableTaskTracker* tracker) {
589  DCHECK(thread_checker_.CalledOnValidThread());
590
591  favicon_base::FaviconRawBitmapResult* result =
592      new favicon_base::FaviconRawBitmapResult();
593  return tracker->PostTaskAndReply(
594      thread_->message_loop_proxy().get(),
595      FROM_HERE,
596      base::Bind(&HistoryBackend::GetLargestFaviconForURL,
597                 history_backend_.get(),
598                 page_url,
599                 icon_types,
600                 minimum_size_in_pixels,
601                 result),
602      base::Bind(&RunWithFaviconResult, callback, base::Owned(result)));
603}
604
605base::CancelableTaskTracker::TaskId HistoryService::GetFaviconForID(
606    favicon_base::FaviconID favicon_id,
607    int desired_size,
608    const favicon_base::FaviconResultsCallback& callback,
609    base::CancelableTaskTracker* tracker) {
610  DCHECK(thread_checker_.CalledOnValidThread());
611
612  std::vector<favicon_base::FaviconRawBitmapResult>* results =
613      new std::vector<favicon_base::FaviconRawBitmapResult>();
614  return tracker->PostTaskAndReply(
615      thread_->message_loop_proxy().get(),
616      FROM_HERE,
617      base::Bind(&HistoryBackend::GetFaviconForID,
618                 history_backend_.get(),
619                 favicon_id,
620                 desired_size,
621                 results),
622      base::Bind(&RunWithFaviconResults, callback, base::Owned(results)));
623}
624
625base::CancelableTaskTracker::TaskId
626HistoryService::UpdateFaviconMappingsAndFetch(
627    const GURL& page_url,
628    const std::vector<GURL>& icon_urls,
629    int icon_types,
630    const std::vector<int>& desired_sizes,
631    const favicon_base::FaviconResultsCallback& callback,
632    base::CancelableTaskTracker* tracker) {
633  DCHECK(thread_checker_.CalledOnValidThread());
634
635  std::vector<favicon_base::FaviconRawBitmapResult>* results =
636      new std::vector<favicon_base::FaviconRawBitmapResult>();
637  return tracker->PostTaskAndReply(
638      thread_->message_loop_proxy().get(),
639      FROM_HERE,
640      base::Bind(&HistoryBackend::UpdateFaviconMappingsAndFetch,
641                 history_backend_.get(),
642                 page_url,
643                 icon_urls,
644                 icon_types,
645                 desired_sizes,
646                 results),
647      base::Bind(&RunWithFaviconResults, callback, base::Owned(results)));
648}
649
650void HistoryService::MergeFavicon(
651    const GURL& page_url,
652    const GURL& icon_url,
653    favicon_base::IconType icon_type,
654    scoped_refptr<base::RefCountedMemory> bitmap_data,
655    const gfx::Size& pixel_size) {
656  DCHECK(thread_checker_.CalledOnValidThread());
657  if (!CanAddURL(page_url))
658    return;
659
660  ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::MergeFavicon, page_url,
661                    icon_url, icon_type, bitmap_data, pixel_size);
662}
663
664void HistoryService::SetFavicons(
665    const GURL& page_url,
666    favicon_base::IconType icon_type,
667    const std::vector<favicon_base::FaviconRawBitmapData>&
668        favicon_bitmap_data) {
669  DCHECK(thread_checker_.CalledOnValidThread());
670  if (!CanAddURL(page_url))
671    return;
672
673  ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::SetFavicons, page_url,
674      icon_type, favicon_bitmap_data);
675}
676
677void HistoryService::SetFaviconsOutOfDateForPage(const GURL& page_url) {
678  DCHECK(thread_checker_.CalledOnValidThread());
679  ScheduleAndForget(PRIORITY_NORMAL,
680                    &HistoryBackend::SetFaviconsOutOfDateForPage, page_url);
681}
682
683void HistoryService::CloneFavicons(const GURL& old_page_url,
684                                   const GURL& new_page_url) {
685  DCHECK(thread_checker_.CalledOnValidThread());
686  ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::CloneFavicons,
687                    old_page_url, new_page_url);
688}
689
690base::CancelableTaskTracker::TaskId HistoryService::QueryURL(
691    const GURL& url,
692    bool want_visits,
693    const QueryURLCallback& callback,
694    base::CancelableTaskTracker* tracker) {
695  DCHECK(thread_checker_.CalledOnValidThread());
696  history::QueryURLResult* query_url_result = new history::QueryURLResult();
697  return tracker->PostTaskAndReply(
698      thread_->message_loop_proxy().get(),
699      FROM_HERE,
700      base::Bind(&HistoryBackend::QueryURL,
701                 history_backend_.get(),
702                 url,
703                 want_visits,
704                 base::Unretained(query_url_result)),
705      base::Bind(
706          &RunWithQueryURLResult, callback, base::Owned(query_url_result)));
707}
708
709// Importer --------------------------------------------------------------------
710
711void HistoryService::SetImportedFavicons(
712    const std::vector<ImportedFaviconUsage>& favicon_usage) {
713  DCHECK(thread_checker_.CalledOnValidThread());
714  ScheduleAndForget(
715      PRIORITY_NORMAL, &HistoryBackend::SetImportedFavicons, favicon_usage);
716}
717
718// Downloads -------------------------------------------------------------------
719
720// Handle creation of a download by creating an entry in the history service's
721// 'downloads' table.
722void HistoryService::CreateDownload(
723    const history::DownloadRow& create_info,
724    const HistoryService::DownloadCreateCallback& callback) {
725  DCHECK(thread_) << "History service being called after cleanup";
726  DCHECK(thread_checker_.CalledOnValidThread());
727  PostTaskAndReplyWithResult(
728      thread_->message_loop_proxy(), FROM_HERE,
729      base::Bind(&HistoryBackend::CreateDownload, history_backend_.get(),
730                 create_info),
731      callback);
732}
733
734void HistoryService::GetNextDownloadId(
735    const content::DownloadIdCallback& callback) {
736  DCHECK(thread_) << "History service being called after cleanup";
737  DCHECK(thread_checker_.CalledOnValidThread());
738  PostTaskAndReplyWithResult(
739      thread_->message_loop_proxy(), FROM_HERE,
740      base::Bind(&HistoryBackend::GetNextDownloadId, history_backend_.get()),
741      callback);
742}
743
744// Handle queries for a list of all downloads in the history database's
745// 'downloads' table.
746void HistoryService::QueryDownloads(
747    const DownloadQueryCallback& callback) {
748  DCHECK(thread_) << "History service being called after cleanup";
749  DCHECK(thread_checker_.CalledOnValidThread());
750  std::vector<history::DownloadRow>* rows =
751    new std::vector<history::DownloadRow>();
752  scoped_ptr<std::vector<history::DownloadRow> > scoped_rows(rows);
753  // Beware! The first Bind() does not simply |scoped_rows.get()| because
754  // base::Passed(&scoped_rows) nullifies |scoped_rows|, and compilers do not
755  // guarantee that the first Bind's arguments are evaluated before the second
756  // Bind's arguments.
757  thread_->message_loop_proxy()->PostTaskAndReply(
758      FROM_HERE,
759      base::Bind(&HistoryBackend::QueryDownloads, history_backend_.get(), rows),
760      base::Bind(callback, base::Passed(&scoped_rows)));
761}
762
763// Handle updates for a particular download. This is a 'fire and forget'
764// operation, so we don't need to be called back.
765void HistoryService::UpdateDownload(const history::DownloadRow& data) {
766  DCHECK(thread_checker_.CalledOnValidThread());
767  ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::UpdateDownload, data);
768}
769
770void HistoryService::RemoveDownloads(const std::set<uint32>& ids) {
771  DCHECK(thread_checker_.CalledOnValidThread());
772  ScheduleAndForget(PRIORITY_NORMAL,
773                    &HistoryBackend::RemoveDownloads, ids);
774}
775
776base::CancelableTaskTracker::TaskId HistoryService::QueryHistory(
777    const base::string16& text_query,
778    const history::QueryOptions& options,
779    const QueryHistoryCallback& callback,
780    base::CancelableTaskTracker* tracker) {
781  DCHECK(thread_checker_.CalledOnValidThread());
782  history::QueryResults* query_results = new history::QueryResults();
783  return tracker->PostTaskAndReply(
784      thread_->message_loop_proxy().get(),
785      FROM_HERE,
786      base::Bind(&HistoryBackend::QueryHistory,
787                 history_backend_.get(),
788                 text_query,
789                 options,
790                 base::Unretained(query_results)),
791      base::Bind(callback, base::Owned(query_results)));
792}
793
794base::CancelableTaskTracker::TaskId HistoryService::QueryRedirectsFrom(
795    const GURL& from_url,
796    const QueryRedirectsCallback& callback,
797    base::CancelableTaskTracker* tracker) {
798  DCHECK(thread_checker_.CalledOnValidThread());
799  history::RedirectList* result = new history::RedirectList();
800  return tracker->PostTaskAndReply(
801      thread_->message_loop_proxy().get(),
802      FROM_HERE,
803      base::Bind(&HistoryBackend::QueryRedirectsFrom,
804                 history_backend_.get(),
805                 from_url,
806                 base::Unretained(result)),
807      base::Bind(callback, base::Owned(result)));
808}
809
810base::CancelableTaskTracker::TaskId HistoryService::QueryRedirectsTo(
811    const GURL& to_url,
812    const QueryRedirectsCallback& callback,
813    base::CancelableTaskTracker* tracker) {
814  DCHECK(thread_checker_.CalledOnValidThread());
815  history::RedirectList* result = new history::RedirectList();
816  return tracker->PostTaskAndReply(thread_->message_loop_proxy().get(),
817                                   FROM_HERE,
818                                   base::Bind(&HistoryBackend::QueryRedirectsTo,
819                                              history_backend_.get(),
820                                              to_url,
821                                              base::Unretained(result)),
822                                   base::Bind(callback, base::Owned(result)));
823}
824
825base::CancelableTaskTracker::TaskId HistoryService::GetVisibleVisitCountToHost(
826    const GURL& url,
827    const GetVisibleVisitCountToHostCallback& callback,
828    base::CancelableTaskTracker* tracker) {
829  DCHECK(thread_checker_.CalledOnValidThread());
830  history::VisibleVisitCountToHostResult* result =
831      new history::VisibleVisitCountToHostResult();
832  return tracker->PostTaskAndReply(
833      thread_->message_loop_proxy().get(),
834      FROM_HERE,
835      base::Bind(&HistoryBackend::GetVisibleVisitCountToHost,
836                 history_backend_.get(),
837                 url,
838                 base::Unretained(result)),
839      base::Bind(&RunWithVisibleVisitCountToHostResult,
840                 callback,
841                 base::Owned(result)));
842}
843
844base::CancelableTaskTracker::TaskId HistoryService::QueryMostVisitedURLs(
845    int result_count,
846    int days_back,
847    const QueryMostVisitedURLsCallback& callback,
848    base::CancelableTaskTracker* tracker) {
849  DCHECK(thread_checker_.CalledOnValidThread());
850  history::MostVisitedURLList* result = new history::MostVisitedURLList();
851  return tracker->PostTaskAndReply(
852      thread_->message_loop_proxy().get(),
853      FROM_HERE,
854      base::Bind(&HistoryBackend::QueryMostVisitedURLs,
855                 history_backend_.get(),
856                 result_count,
857                 days_back,
858                 base::Unretained(result)),
859      base::Bind(callback, base::Owned(result)));
860}
861
862base::CancelableTaskTracker::TaskId HistoryService::QueryFilteredURLs(
863    int result_count,
864    const history::VisitFilter& filter,
865    bool extended_info,
866    const QueryFilteredURLsCallback& callback,
867    base::CancelableTaskTracker* tracker) {
868  DCHECK(thread_checker_.CalledOnValidThread());
869  history::FilteredURLList* result = new history::FilteredURLList();
870  return tracker->PostTaskAndReply(
871      thread_->message_loop_proxy().get(),
872      FROM_HERE,
873      base::Bind(&HistoryBackend::QueryFilteredURLs,
874                 history_backend_.get(),
875                 result_count,
876                 filter,
877                 extended_info,
878                 base::Unretained(result)),
879      base::Bind(callback, base::Owned(result)));
880}
881
882void HistoryService::Observe(int type,
883                             const content::NotificationSource& source,
884                             const content::NotificationDetails& details) {
885  DCHECK(thread_checker_.CalledOnValidThread());
886  if (!thread_)
887    return;
888
889  switch (type) {
890    case chrome::NOTIFICATION_HISTORY_URLS_DELETED: {
891      // Update the visited link system for deleted URLs. We will update the
892      // visited link system for added URLs as soon as we get the add
893      // notification (we don't have to wait for the backend, which allows us to
894      // be faster to update the state).
895      //
896      // For deleted URLs, we don't typically know what will be deleted since
897      // delete notifications are by time. We would also like to be more
898      // respectful of privacy and never tell the user something is gone when it
899      // isn't. Therefore, we update the delete URLs after the fact.
900      if (visitedlink_master_) {
901        content::Details<history::URLsDeletedDetails> deleted_details(details);
902
903        if (deleted_details->all_history) {
904          visitedlink_master_->DeleteAllURLs();
905        } else {
906          URLIteratorFromURLRows iterator(deleted_details->rows);
907          visitedlink_master_->DeleteURLs(&iterator);
908        }
909      }
910      break;
911    }
912
913    default:
914      NOTREACHED();
915  }
916}
917
918void HistoryService::RebuildTable(
919    const scoped_refptr<URLEnumerator>& enumerator) {
920  DCHECK(thread_checker_.CalledOnValidThread());
921  ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::IterateURLs, enumerator);
922}
923
924bool HistoryService::Init(const base::FilePath& history_dir, bool no_db) {
925  DCHECK(thread_checker_.CalledOnValidThread());
926  base::Thread::Options options;
927  options.timer_slack = base::TIMER_SLACK_MAXIMUM;
928  if (!thread_->StartWithOptions(options)) {
929    Cleanup();
930    return false;
931  }
932
933  history_dir_ = history_dir;
934  no_db_ = no_db;
935
936  if (profile_) {
937    std::string languages =
938        profile_->GetPrefs()->GetString(prefs::kAcceptLanguages);
939    in_memory_url_index_.reset(new history::InMemoryURLIndex(
940        profile_, history_dir_, languages, history_client_));
941    in_memory_url_index_->Init();
942  }
943
944  // Create the history backend.
945  scoped_refptr<HistoryBackend> backend(
946      new HistoryBackend(history_dir_,
947                         new BackendDelegate(
948                             weak_ptr_factory_.GetWeakPtr(),
949                             base::ThreadTaskRunnerHandle::Get(),
950                             profile_),
951                         history_client_));
952  history_backend_.swap(backend);
953
954  // There may not be a profile when unit testing.
955  std::string languages;
956  if (profile_) {
957    PrefService* prefs = profile_->GetPrefs();
958    languages = prefs->GetString(prefs::kAcceptLanguages);
959  }
960  ScheduleAndForget(PRIORITY_UI, &HistoryBackend::Init, languages, no_db_);
961
962  if (visitedlink_master_) {
963    bool result = visitedlink_master_->Init();
964    DCHECK(result);
965  }
966
967  return true;
968}
969
970void HistoryService::ScheduleAutocomplete(const base::Callback<
971    void(history::HistoryBackend*, history::URLDatabase*)>& callback) {
972  DCHECK(thread_checker_.CalledOnValidThread());
973  ScheduleAndForget(
974      PRIORITY_UI, &HistoryBackend::ScheduleAutocomplete, callback);
975}
976
977void HistoryService::ScheduleTask(SchedulePriority priority,
978                                  const base::Closure& task) {
979  DCHECK(thread_checker_.CalledOnValidThread());
980  CHECK(thread_);
981  CHECK(thread_->message_loop());
982  // TODO(brettw): Do prioritization.
983  thread_->message_loop()->PostTask(FROM_HERE, task);
984}
985
986// static
987bool HistoryService::CanAddURL(const GURL& url) {
988  if (!url.is_valid())
989    return false;
990
991  // TODO: We should allow kChromeUIScheme URLs if they have been explicitly
992  // typed.  Right now, however, these are marked as typed even when triggered
993  // by a shortcut or menu action.
994  if (url.SchemeIs(url::kJavaScriptScheme) ||
995      url.SchemeIs(content::kChromeDevToolsScheme) ||
996      url.SchemeIs(content::kChromeUIScheme) ||
997      url.SchemeIs(content::kViewSourceScheme) ||
998      url.SchemeIs(chrome::kChromeNativeScheme) ||
999      url.SchemeIs(chrome::kChromeSearchScheme) ||
1000      url.SchemeIs(chrome::kDomDistillerScheme))
1001    return false;
1002
1003  // Allow all about: and chrome: URLs except about:blank, since the user may
1004  // like to see "chrome://memory/", etc. in their history and autocomplete.
1005  if (url == GURL(url::kAboutBlankURL))
1006    return false;
1007
1008  return true;
1009}
1010
1011base::WeakPtr<HistoryService> HistoryService::AsWeakPtr() {
1012  DCHECK(thread_checker_.CalledOnValidThread());
1013  return weak_ptr_factory_.GetWeakPtr();
1014}
1015
1016syncer::SyncMergeResult HistoryService::MergeDataAndStartSyncing(
1017    syncer::ModelType type,
1018    const syncer::SyncDataList& initial_sync_data,
1019    scoped_ptr<syncer::SyncChangeProcessor> sync_processor,
1020    scoped_ptr<syncer::SyncErrorFactory> error_handler) {
1021  DCHECK(thread_checker_.CalledOnValidThread());
1022  DCHECK_EQ(type, syncer::HISTORY_DELETE_DIRECTIVES);
1023  delete_directive_handler_.Start(this, initial_sync_data,
1024                                  sync_processor.Pass());
1025  return syncer::SyncMergeResult(type);
1026}
1027
1028void HistoryService::StopSyncing(syncer::ModelType type) {
1029  DCHECK(thread_checker_.CalledOnValidThread());
1030  DCHECK_EQ(type, syncer::HISTORY_DELETE_DIRECTIVES);
1031  delete_directive_handler_.Stop();
1032}
1033
1034syncer::SyncDataList HistoryService::GetAllSyncData(
1035    syncer::ModelType type) const {
1036  DCHECK(thread_checker_.CalledOnValidThread());
1037  DCHECK_EQ(type, syncer::HISTORY_DELETE_DIRECTIVES);
1038  // TODO(akalin): Keep track of existing delete directives.
1039  return syncer::SyncDataList();
1040}
1041
1042syncer::SyncError HistoryService::ProcessSyncChanges(
1043    const tracked_objects::Location& from_here,
1044    const syncer::SyncChangeList& change_list) {
1045  delete_directive_handler_.ProcessSyncChanges(this, change_list);
1046  return syncer::SyncError();
1047}
1048
1049syncer::SyncError HistoryService::ProcessLocalDeleteDirective(
1050    const sync_pb::HistoryDeleteDirectiveSpecifics& delete_directive) {
1051  DCHECK(thread_checker_.CalledOnValidThread());
1052  return delete_directive_handler_.ProcessLocalDeleteDirective(
1053      delete_directive);
1054}
1055
1056void HistoryService::SetInMemoryBackend(
1057    scoped_ptr<history::InMemoryHistoryBackend> mem_backend) {
1058  DCHECK(thread_checker_.CalledOnValidThread());
1059  DCHECK(!in_memory_backend_) << "Setting mem DB twice";
1060  in_memory_backend_.reset(mem_backend.release());
1061
1062  // The database requires additional initialization once we own it.
1063  in_memory_backend_->AttachToHistoryService(profile_);
1064}
1065
1066void HistoryService::NotifyProfileError(sql::InitStatus init_status) {
1067  DCHECK(thread_checker_.CalledOnValidThread());
1068  if (history_client_)
1069    history_client_->NotifyProfileError(init_status);
1070}
1071
1072void HistoryService::DeleteURL(const GURL& url) {
1073  DCHECK(thread_checker_.CalledOnValidThread());
1074  // We will update the visited links when we observe the delete notifications.
1075  ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::DeleteURL, url);
1076}
1077
1078void HistoryService::DeleteURLsForTest(const std::vector<GURL>& urls) {
1079  DCHECK(thread_checker_.CalledOnValidThread());
1080  // We will update the visited links when we observe the delete
1081  // notifications.
1082  ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::DeleteURLs, urls);
1083}
1084
1085void HistoryService::ExpireHistoryBetween(
1086    const std::set<GURL>& restrict_urls,
1087    Time begin_time,
1088    Time end_time,
1089    const base::Closure& callback,
1090    base::CancelableTaskTracker* tracker) {
1091  DCHECK(thread_);
1092  DCHECK(thread_checker_.CalledOnValidThread());
1093  DCHECK(history_backend_.get());
1094  tracker->PostTaskAndReply(thread_->message_loop_proxy().get(),
1095                            FROM_HERE,
1096                            base::Bind(&HistoryBackend::ExpireHistoryBetween,
1097                                       history_backend_,
1098                                       restrict_urls,
1099                                       begin_time,
1100                                       end_time),
1101                            callback);
1102}
1103
1104void HistoryService::ExpireHistory(
1105    const std::vector<history::ExpireHistoryArgs>& expire_list,
1106    const base::Closure& callback,
1107    base::CancelableTaskTracker* tracker) {
1108  DCHECK(thread_);
1109  DCHECK(thread_checker_.CalledOnValidThread());
1110  DCHECK(history_backend_.get());
1111  tracker->PostTaskAndReply(
1112      thread_->message_loop_proxy().get(),
1113      FROM_HERE,
1114      base::Bind(&HistoryBackend::ExpireHistory, history_backend_, expire_list),
1115      callback);
1116}
1117
1118void HistoryService::ExpireLocalAndRemoteHistoryBetween(
1119    const std::set<GURL>& restrict_urls,
1120    Time begin_time,
1121    Time end_time,
1122    const base::Closure& callback,
1123    base::CancelableTaskTracker* tracker) {
1124  // TODO(dubroy): This should be factored out into a separate class that
1125  // dispatches deletions to the proper places.
1126
1127  history::WebHistoryService* web_history =
1128      WebHistoryServiceFactory::GetForProfile(profile_);
1129  if (web_history) {
1130    // TODO(dubroy): This API does not yet support deletion of specific URLs.
1131    DCHECK(restrict_urls.empty());
1132
1133    delete_directive_handler_.CreateDeleteDirectives(
1134        std::set<int64>(), begin_time, end_time);
1135
1136    // Attempt online deletion from the history server, but ignore the result.
1137    // Deletion directives ensure that the results will eventually be deleted.
1138    //
1139    // TODO(davidben): |callback| should not run until this operation completes
1140    // too.
1141    web_history->ExpireHistoryBetween(
1142        restrict_urls, begin_time, end_time,
1143        base::Bind(&ExpireWebHistoryComplete));
1144  }
1145  ExpireHistoryBetween(restrict_urls, begin_time, end_time, callback, tracker);
1146}
1147
1148void HistoryService::BroadcastNotificationsHelper(
1149    int type,
1150    scoped_ptr<history::HistoryDetails> details) {
1151  DCHECK(thread_checker_.CalledOnValidThread());
1152  // TODO(evanm): this is currently necessitated by generate_profile, which
1153  // runs without a browser process. generate_profile should really create
1154  // a browser process, at which point this check can then be nuked.
1155  if (!g_browser_process)
1156    return;
1157
1158  if (!thread_)
1159    return;
1160
1161  // The source of all of our notifications is the profile. Note that this
1162  // pointer is NULL in unit tests.
1163  content::Source<Profile> source(profile_);
1164
1165  // The details object just contains the pointer to the object that the
1166  // backend has allocated for us. The receiver of the notification will cast
1167  // this to the proper type.
1168  content::Details<history::HistoryDetails> det(details.get());
1169
1170  content::NotificationService::current()->Notify(type, source, det);
1171}
1172
1173void HistoryService::OnDBLoaded() {
1174  DCHECK(thread_checker_.CalledOnValidThread());
1175  backend_loaded_ = true;
1176  content::NotificationService::current()->Notify(
1177      chrome::NOTIFICATION_HISTORY_LOADED,
1178      content::Source<Profile>(profile_),
1179      content::Details<HistoryService>(this));
1180}
1181
1182bool HistoryService::GetRowForURL(const GURL& url, history::URLRow* url_row) {
1183  DCHECK(thread_checker_.CalledOnValidThread());
1184  history::URLDatabase* db = InMemoryDatabase();
1185  return db && (db->GetRowForURL(url, url_row) != 0);
1186}
1187
1188void HistoryService::AddVisitDatabaseObserver(
1189    history::VisitDatabaseObserver* observer) {
1190  DCHECK(thread_checker_.CalledOnValidThread());
1191  visit_database_observers_.AddObserver(observer);
1192}
1193
1194void HistoryService::RemoveVisitDatabaseObserver(
1195    history::VisitDatabaseObserver* observer) {
1196  DCHECK(thread_checker_.CalledOnValidThread());
1197  visit_database_observers_.RemoveObserver(observer);
1198}
1199
1200void HistoryService::NotifyVisitDBObserversOnAddVisit(
1201    const history::BriefVisitInfo& info) {
1202  DCHECK(thread_checker_.CalledOnValidThread());
1203  FOR_EACH_OBSERVER(history::VisitDatabaseObserver, visit_database_observers_,
1204                    OnAddVisit(info));
1205}
1206