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