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