history_service.cc revision f8ee788a64d60abd8f2d742a5fdedde054ecd910
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    int desired_size_in_dip,
551    const std::vector<ui::ScaleFactor>& desired_scale_factors,
552    const favicon_base::FaviconResultsCallback& callback,
553    base::CancelableTaskTracker* tracker) {
554  DCHECK(thread_checker_.CalledOnValidThread());
555
556  std::vector<favicon_base::FaviconRawBitmapResult>* results =
557      new std::vector<favicon_base::FaviconRawBitmapResult>();
558  return tracker->PostTaskAndReply(
559      thread_->message_loop_proxy().get(),
560      FROM_HERE,
561      base::Bind(&HistoryBackend::GetFavicons,
562                 history_backend_.get(),
563                 icon_urls,
564                 icon_types,
565                 desired_size_in_dip,
566                 desired_scale_factors,
567                 results),
568      base::Bind(&RunWithFaviconResults, callback, base::Owned(results)));
569}
570
571base::CancelableTaskTracker::TaskId HistoryService::GetFaviconsForURL(
572    const GURL& page_url,
573    int icon_types,
574    int desired_size_in_dip,
575    const std::vector<ui::ScaleFactor>& desired_scale_factors,
576    const favicon_base::FaviconResultsCallback& callback,
577    base::CancelableTaskTracker* tracker) {
578  DCHECK(thread_checker_.CalledOnValidThread());
579
580  std::vector<favicon_base::FaviconRawBitmapResult>* results =
581      new std::vector<favicon_base::FaviconRawBitmapResult>();
582  return tracker->PostTaskAndReply(
583      thread_->message_loop_proxy().get(),
584      FROM_HERE,
585      base::Bind(&HistoryBackend::GetFaviconsForURL,
586                 history_backend_.get(),
587                 page_url,
588                 icon_types,
589                 desired_size_in_dip,
590                 desired_scale_factors,
591                 results),
592      base::Bind(&RunWithFaviconResults, callback, base::Owned(results)));
593}
594
595base::CancelableTaskTracker::TaskId HistoryService::GetLargestFaviconForURL(
596    const GURL& page_url,
597    const std::vector<int>& icon_types,
598    int minimum_size_in_pixels,
599    const favicon_base::FaviconRawBitmapCallback& callback,
600    base::CancelableTaskTracker* tracker) {
601  DCHECK(thread_checker_.CalledOnValidThread());
602
603  favicon_base::FaviconRawBitmapResult* result =
604      new favicon_base::FaviconRawBitmapResult();
605  return tracker->PostTaskAndReply(
606      thread_->message_loop_proxy().get(),
607      FROM_HERE,
608      base::Bind(&HistoryBackend::GetLargestFaviconForURL,
609                 history_backend_.get(),
610                 page_url,
611                 icon_types,
612                 minimum_size_in_pixels,
613                 result),
614      base::Bind(&RunWithFaviconResult, callback, base::Owned(result)));
615}
616
617base::CancelableTaskTracker::TaskId HistoryService::GetFaviconForID(
618    favicon_base::FaviconID favicon_id,
619    int desired_size_in_dip,
620    ui::ScaleFactor desired_scale_factor,
621    const favicon_base::FaviconResultsCallback& callback,
622    base::CancelableTaskTracker* tracker) {
623  DCHECK(thread_checker_.CalledOnValidThread());
624
625  std::vector<favicon_base::FaviconRawBitmapResult>* results =
626      new std::vector<favicon_base::FaviconRawBitmapResult>();
627  return tracker->PostTaskAndReply(
628      thread_->message_loop_proxy().get(),
629      FROM_HERE,
630      base::Bind(&HistoryBackend::GetFaviconForID,
631                 history_backend_.get(),
632                 favicon_id,
633                 desired_size_in_dip,
634                 desired_scale_factor,
635                 results),
636      base::Bind(&RunWithFaviconResults, callback, base::Owned(results)));
637}
638
639base::CancelableTaskTracker::TaskId
640HistoryService::UpdateFaviconMappingsAndFetch(
641    const GURL& page_url,
642    const std::vector<GURL>& icon_urls,
643    int icon_types,
644    int desired_size_in_dip,
645    const std::vector<ui::ScaleFactor>& desired_scale_factors,
646    const favicon_base::FaviconResultsCallback& callback,
647    base::CancelableTaskTracker* tracker) {
648  DCHECK(thread_checker_.CalledOnValidThread());
649
650  std::vector<favicon_base::FaviconRawBitmapResult>* results =
651      new std::vector<favicon_base::FaviconRawBitmapResult>();
652  return tracker->PostTaskAndReply(
653      thread_->message_loop_proxy().get(),
654      FROM_HERE,
655      base::Bind(&HistoryBackend::UpdateFaviconMappingsAndFetch,
656                 history_backend_.get(),
657                 page_url,
658                 icon_urls,
659                 icon_types,
660                 desired_size_in_dip,
661                 desired_scale_factors,
662                 results),
663      base::Bind(&RunWithFaviconResults, callback, base::Owned(results)));
664}
665
666void HistoryService::MergeFavicon(
667    const GURL& page_url,
668    const GURL& icon_url,
669    favicon_base::IconType icon_type,
670    scoped_refptr<base::RefCountedMemory> bitmap_data,
671    const gfx::Size& pixel_size) {
672  DCHECK(thread_checker_.CalledOnValidThread());
673  if (!CanAddURL(page_url))
674    return;
675
676  ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::MergeFavicon, page_url,
677                    icon_url, icon_type, bitmap_data, pixel_size);
678}
679
680void HistoryService::SetFavicons(
681    const GURL& page_url,
682    favicon_base::IconType icon_type,
683    const std::vector<favicon_base::FaviconRawBitmapData>&
684        favicon_bitmap_data) {
685  DCHECK(thread_checker_.CalledOnValidThread());
686  if (!CanAddURL(page_url))
687    return;
688
689  ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::SetFavicons, page_url,
690      icon_type, favicon_bitmap_data);
691}
692
693void HistoryService::SetFaviconsOutOfDateForPage(const GURL& page_url) {
694  DCHECK(thread_checker_.CalledOnValidThread());
695  ScheduleAndForget(PRIORITY_NORMAL,
696                    &HistoryBackend::SetFaviconsOutOfDateForPage, page_url);
697}
698
699void HistoryService::CloneFavicons(const GURL& old_page_url,
700                                   const GURL& new_page_url) {
701  DCHECK(thread_checker_.CalledOnValidThread());
702  ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::CloneFavicons,
703                    old_page_url, new_page_url);
704}
705
706void HistoryService::SetImportedFavicons(
707    const std::vector<ImportedFaviconUsage>& favicon_usage) {
708  DCHECK(thread_checker_.CalledOnValidThread());
709  ScheduleAndForget(PRIORITY_NORMAL,
710                    &HistoryBackend::SetImportedFavicons, favicon_usage);
711}
712
713base::CancelableTaskTracker::TaskId HistoryService::QueryURL(
714    const GURL& url,
715    bool want_visits,
716    const QueryURLCallback& callback,
717    base::CancelableTaskTracker* tracker) {
718  DCHECK(thread_checker_.CalledOnValidThread());
719  return PostTaskAndReplyWithResult(
720      thread_->message_loop_proxy().get(),
721      FROM_HERE,
722      base::Bind(
723          &HistoryBackend::QueryURL, history_backend_.get(), url, want_visits),
724      base::Bind(&RunWithQueryURLResult, callback));
725}
726
727// Downloads -------------------------------------------------------------------
728
729// Handle creation of a download by creating an entry in the history service's
730// 'downloads' table.
731void HistoryService::CreateDownload(
732    const history::DownloadRow& create_info,
733    const HistoryService::DownloadCreateCallback& 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::CreateDownload, history_backend_.get(),
739                 create_info),
740      callback);
741}
742
743void HistoryService::GetNextDownloadId(
744    const content::DownloadIdCallback& callback) {
745  DCHECK(thread_) << "History service being called after cleanup";
746  DCHECK(thread_checker_.CalledOnValidThread());
747  PostTaskAndReplyWithResult(
748      thread_->message_loop_proxy(), FROM_HERE,
749      base::Bind(&HistoryBackend::GetNextDownloadId, history_backend_.get()),
750      callback);
751}
752
753// Handle queries for a list of all downloads in the history database's
754// 'downloads' table.
755void HistoryService::QueryDownloads(
756    const DownloadQueryCallback& callback) {
757  DCHECK(thread_) << "History service being called after cleanup";
758  DCHECK(thread_checker_.CalledOnValidThread());
759  std::vector<history::DownloadRow>* rows =
760    new std::vector<history::DownloadRow>();
761  scoped_ptr<std::vector<history::DownloadRow> > scoped_rows(rows);
762  // Beware! The first Bind() does not simply |scoped_rows.get()| because
763  // base::Passed(&scoped_rows) nullifies |scoped_rows|, and compilers do not
764  // guarantee that the first Bind's arguments are evaluated before the second
765  // Bind's arguments.
766  thread_->message_loop_proxy()->PostTaskAndReply(
767      FROM_HERE,
768      base::Bind(&HistoryBackend::QueryDownloads, history_backend_.get(), rows),
769      base::Bind(callback, base::Passed(&scoped_rows)));
770}
771
772// Handle updates for a particular download. This is a 'fire and forget'
773// operation, so we don't need to be called back.
774void HistoryService::UpdateDownload(const history::DownloadRow& data) {
775  DCHECK(thread_checker_.CalledOnValidThread());
776  ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::UpdateDownload, data);
777}
778
779void HistoryService::RemoveDownloads(const std::set<uint32>& ids) {
780  DCHECK(thread_checker_.CalledOnValidThread());
781  ScheduleAndForget(PRIORITY_NORMAL,
782                    &HistoryBackend::RemoveDownloads, ids);
783}
784
785HistoryService::Handle HistoryService::QueryHistory(
786    const base::string16& text_query,
787    const history::QueryOptions& options,
788    CancelableRequestConsumerBase* consumer,
789    const QueryHistoryCallback& callback) {
790  DCHECK(thread_checker_.CalledOnValidThread());
791  return Schedule(PRIORITY_UI, &HistoryBackend::QueryHistory, consumer,
792                  new history::QueryHistoryRequest(callback),
793                  text_query, options);
794}
795
796HistoryService::Handle HistoryService::QueryRedirectsFrom(
797    const GURL& from_url,
798    CancelableRequestConsumerBase* consumer,
799    const QueryRedirectsCallback& callback) {
800  DCHECK(thread_checker_.CalledOnValidThread());
801  return Schedule(PRIORITY_UI, &HistoryBackend::QueryRedirectsFrom, consumer,
802      new history::QueryRedirectsRequest(callback), from_url);
803}
804
805HistoryService::Handle HistoryService::QueryRedirectsTo(
806    const GURL& to_url,
807    CancelableRequestConsumerBase* consumer,
808    const QueryRedirectsCallback& callback) {
809  DCHECK(thread_checker_.CalledOnValidThread());
810  return Schedule(PRIORITY_NORMAL, &HistoryBackend::QueryRedirectsTo, consumer,
811      new history::QueryRedirectsRequest(callback), to_url);
812}
813
814HistoryService::Handle HistoryService::GetVisibleVisitCountToHost(
815    const GURL& url,
816    CancelableRequestConsumerBase* consumer,
817    const GetVisibleVisitCountToHostCallback& callback) {
818  DCHECK(thread_checker_.CalledOnValidThread());
819  return Schedule(PRIORITY_UI, &HistoryBackend::GetVisibleVisitCountToHost,
820      consumer, new history::GetVisibleVisitCountToHostRequest(callback), url);
821}
822
823HistoryService::Handle HistoryService::QueryTopURLsAndRedirects(
824    int result_count,
825    CancelableRequestConsumerBase* consumer,
826    const QueryTopURLsAndRedirectsCallback& callback) {
827  DCHECK(thread_checker_.CalledOnValidThread());
828  return Schedule(PRIORITY_NORMAL, &HistoryBackend::QueryTopURLsAndRedirects,
829      consumer, new history::QueryTopURLsAndRedirectsRequest(callback),
830      result_count);
831}
832
833HistoryService::Handle HistoryService::QueryMostVisitedURLs(
834    int result_count,
835    int days_back,
836    CancelableRequestConsumerBase* consumer,
837    const QueryMostVisitedURLsCallback& callback) {
838  DCHECK(thread_checker_.CalledOnValidThread());
839  return Schedule(PRIORITY_NORMAL, &HistoryBackend::QueryMostVisitedURLs,
840                  consumer,
841                  new history::QueryMostVisitedURLsRequest(callback),
842                  result_count, days_back);
843}
844
845HistoryService::Handle HistoryService::QueryFilteredURLs(
846    int result_count,
847    const history::VisitFilter& filter,
848    bool extended_info,
849    CancelableRequestConsumerBase* consumer,
850    const QueryFilteredURLsCallback& callback) {
851  DCHECK(thread_checker_.CalledOnValidThread());
852  return Schedule(PRIORITY_NORMAL,
853                  &HistoryBackend::QueryFilteredURLs,
854                  consumer,
855                  new history::QueryFilteredURLsRequest(callback),
856                  result_count, filter, extended_info);
857}
858
859void HistoryService::Observe(int type,
860                             const content::NotificationSource& source,
861                             const content::NotificationDetails& details) {
862  DCHECK(thread_checker_.CalledOnValidThread());
863  if (!thread_)
864    return;
865
866  switch (type) {
867    case chrome::NOTIFICATION_HISTORY_URLS_DELETED: {
868      // Update the visited link system for deleted URLs. We will update the
869      // visited link system for added URLs as soon as we get the add
870      // notification (we don't have to wait for the backend, which allows us to
871      // be faster to update the state).
872      //
873      // For deleted URLs, we don't typically know what will be deleted since
874      // delete notifications are by time. We would also like to be more
875      // respectful of privacy and never tell the user something is gone when it
876      // isn't. Therefore, we update the delete URLs after the fact.
877      if (visitedlink_master_) {
878        content::Details<history::URLsDeletedDetails> deleted_details(details);
879
880        if (deleted_details->all_history) {
881          visitedlink_master_->DeleteAllURLs();
882        } else {
883          URLIteratorFromURLRows iterator(deleted_details->rows);
884          visitedlink_master_->DeleteURLs(&iterator);
885        }
886      }
887      break;
888    }
889
890    case chrome::NOTIFICATION_TEMPLATE_URL_REMOVED:
891      DeleteAllSearchTermsForKeyword(
892          *(content::Details<TemplateURLID>(details).ptr()));
893      break;
894
895    default:
896      NOTREACHED();
897  }
898}
899
900void HistoryService::RebuildTable(
901    const scoped_refptr<URLEnumerator>& enumerator) {
902  DCHECK(thread_checker_.CalledOnValidThread());
903  ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::IterateURLs, enumerator);
904}
905
906bool HistoryService::Init(const base::FilePath& history_dir, bool no_db) {
907  DCHECK(thread_checker_.CalledOnValidThread());
908  if (!thread_->Start()) {
909    Cleanup();
910    return false;
911  }
912
913  history_dir_ = history_dir;
914  no_db_ = no_db;
915
916  if (profile_) {
917    std::string languages =
918        profile_->GetPrefs()->GetString(prefs::kAcceptLanguages);
919    in_memory_url_index_.reset(new history::InMemoryURLIndex(
920        profile_, history_dir_, languages, history_client_));
921    in_memory_url_index_->Init();
922  }
923
924  // Create the history backend.
925  scoped_refptr<HistoryBackend> backend(
926      new HistoryBackend(history_dir_,
927                         new BackendDelegate(
928                             weak_ptr_factory_.GetWeakPtr(),
929                             base::ThreadTaskRunnerHandle::Get(),
930                             profile_),
931                         history_client_));
932  history_backend_.swap(backend);
933
934  // There may not be a profile when unit testing.
935  std::string languages;
936  if (profile_) {
937    PrefService* prefs = profile_->GetPrefs();
938    languages = prefs->GetString(prefs::kAcceptLanguages);
939  }
940  ScheduleAndForget(PRIORITY_UI, &HistoryBackend::Init, languages, no_db_);
941
942  if (visitedlink_master_) {
943    bool result = visitedlink_master_->Init();
944    DCHECK(result);
945  }
946
947  return true;
948}
949
950void HistoryService::ScheduleAutocomplete(HistoryURLProvider* provider,
951                                          HistoryURLProviderParams* params) {
952  DCHECK(thread_checker_.CalledOnValidThread());
953  ScheduleAndForget(PRIORITY_UI, &HistoryBackend::ScheduleAutocomplete,
954                    scoped_refptr<HistoryURLProvider>(provider), params);
955}
956
957void HistoryService::ScheduleTask(SchedulePriority priority,
958                                  const base::Closure& task) {
959  DCHECK(thread_checker_.CalledOnValidThread());
960  CHECK(thread_);
961  CHECK(thread_->message_loop());
962  // TODO(brettw): Do prioritization.
963  thread_->message_loop()->PostTask(FROM_HERE, task);
964}
965
966// static
967bool HistoryService::CanAddURL(const GURL& url) {
968  if (!url.is_valid())
969    return false;
970
971  // TODO: We should allow kChromeUIScheme URLs if they have been explicitly
972  // typed.  Right now, however, these are marked as typed even when triggered
973  // by a shortcut or menu action.
974  if (url.SchemeIs(url::kJavaScriptScheme) ||
975      url.SchemeIs(content::kChromeDevToolsScheme) ||
976      url.SchemeIs(content::kChromeUIScheme) ||
977      url.SchemeIs(content::kViewSourceScheme) ||
978      url.SchemeIs(chrome::kChromeNativeScheme) ||
979      url.SchemeIs(chrome::kChromeSearchScheme) ||
980      url.SchemeIs(chrome::kDomDistillerScheme))
981    return false;
982
983  // Allow all about: and chrome: URLs except about:blank, since the user may
984  // like to see "chrome://memory/", etc. in their history and autocomplete.
985  if (url == GURL(url::kAboutBlankURL))
986    return false;
987
988  return true;
989}
990
991base::WeakPtr<HistoryService> HistoryService::AsWeakPtr() {
992  DCHECK(thread_checker_.CalledOnValidThread());
993  return weak_ptr_factory_.GetWeakPtr();
994}
995
996syncer::SyncMergeResult HistoryService::MergeDataAndStartSyncing(
997    syncer::ModelType type,
998    const syncer::SyncDataList& initial_sync_data,
999    scoped_ptr<syncer::SyncChangeProcessor> sync_processor,
1000    scoped_ptr<syncer::SyncErrorFactory> error_handler) {
1001  DCHECK(thread_checker_.CalledOnValidThread());
1002  DCHECK_EQ(type, syncer::HISTORY_DELETE_DIRECTIVES);
1003  delete_directive_handler_.Start(this, initial_sync_data,
1004                                  sync_processor.Pass());
1005  return syncer::SyncMergeResult(type);
1006}
1007
1008void HistoryService::StopSyncing(syncer::ModelType type) {
1009  DCHECK(thread_checker_.CalledOnValidThread());
1010  DCHECK_EQ(type, syncer::HISTORY_DELETE_DIRECTIVES);
1011  delete_directive_handler_.Stop();
1012}
1013
1014syncer::SyncDataList HistoryService::GetAllSyncData(
1015    syncer::ModelType type) const {
1016  DCHECK(thread_checker_.CalledOnValidThread());
1017  DCHECK_EQ(type, syncer::HISTORY_DELETE_DIRECTIVES);
1018  // TODO(akalin): Keep track of existing delete directives.
1019  return syncer::SyncDataList();
1020}
1021
1022syncer::SyncError HistoryService::ProcessSyncChanges(
1023    const tracked_objects::Location& from_here,
1024    const syncer::SyncChangeList& change_list) {
1025  delete_directive_handler_.ProcessSyncChanges(this, change_list);
1026  return syncer::SyncError();
1027}
1028
1029syncer::SyncError HistoryService::ProcessLocalDeleteDirective(
1030    const sync_pb::HistoryDeleteDirectiveSpecifics& delete_directive) {
1031  DCHECK(thread_checker_.CalledOnValidThread());
1032  return delete_directive_handler_.ProcessLocalDeleteDirective(
1033      delete_directive);
1034}
1035
1036void HistoryService::SetInMemoryBackend(
1037    scoped_ptr<history::InMemoryHistoryBackend> mem_backend) {
1038  DCHECK(thread_checker_.CalledOnValidThread());
1039  DCHECK(!in_memory_backend_) << "Setting mem DB twice";
1040  in_memory_backend_.reset(mem_backend.release());
1041
1042  // The database requires additional initialization once we own it.
1043  in_memory_backend_->AttachToHistoryService(profile_);
1044}
1045
1046void HistoryService::NotifyProfileError(sql::InitStatus init_status) {
1047  DCHECK(thread_checker_.CalledOnValidThread());
1048  if (history_client_)
1049    history_client_->NotifyProfileError(init_status);
1050}
1051
1052void HistoryService::DeleteURL(const GURL& url) {
1053  DCHECK(thread_checker_.CalledOnValidThread());
1054  // We will update the visited links when we observe the delete notifications.
1055  ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::DeleteURL, url);
1056}
1057
1058void HistoryService::DeleteURLsForTest(const std::vector<GURL>& urls) {
1059  DCHECK(thread_checker_.CalledOnValidThread());
1060  // We will update the visited links when we observe the delete
1061  // notifications.
1062  ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::DeleteURLs, urls);
1063}
1064
1065void HistoryService::ExpireHistoryBetween(
1066    const std::set<GURL>& restrict_urls,
1067    Time begin_time,
1068    Time end_time,
1069    const base::Closure& callback,
1070    base::CancelableTaskTracker* tracker) {
1071  DCHECK(thread_);
1072  DCHECK(thread_checker_.CalledOnValidThread());
1073  DCHECK(history_backend_.get());
1074  tracker->PostTaskAndReply(thread_->message_loop_proxy().get(),
1075                            FROM_HERE,
1076                            base::Bind(&HistoryBackend::ExpireHistoryBetween,
1077                                       history_backend_,
1078                                       restrict_urls,
1079                                       begin_time,
1080                                       end_time),
1081                            callback);
1082}
1083
1084void HistoryService::ExpireHistory(
1085    const std::vector<history::ExpireHistoryArgs>& expire_list,
1086    const base::Closure& callback,
1087    base::CancelableTaskTracker* tracker) {
1088  DCHECK(thread_);
1089  DCHECK(thread_checker_.CalledOnValidThread());
1090  DCHECK(history_backend_.get());
1091  tracker->PostTaskAndReply(
1092      thread_->message_loop_proxy().get(),
1093      FROM_HERE,
1094      base::Bind(&HistoryBackend::ExpireHistory, history_backend_, expire_list),
1095      callback);
1096}
1097
1098void HistoryService::ExpireLocalAndRemoteHistoryBetween(
1099    const std::set<GURL>& restrict_urls,
1100    Time begin_time,
1101    Time end_time,
1102    const base::Closure& callback,
1103    base::CancelableTaskTracker* tracker) {
1104  // TODO(dubroy): This should be factored out into a separate class that
1105  // dispatches deletions to the proper places.
1106
1107  history::WebHistoryService* web_history =
1108      WebHistoryServiceFactory::GetForProfile(profile_);
1109  if (web_history) {
1110    // TODO(dubroy): This API does not yet support deletion of specific URLs.
1111    DCHECK(restrict_urls.empty());
1112
1113    delete_directive_handler_.CreateDeleteDirectives(
1114        std::set<int64>(), begin_time, end_time);
1115
1116    // Attempt online deletion from the history server, but ignore the result.
1117    // Deletion directives ensure that the results will eventually be deleted.
1118    //
1119    // TODO(davidben): |callback| should not run until this operation completes
1120    // too.
1121    web_history->ExpireHistoryBetween(
1122        restrict_urls, begin_time, end_time,
1123        base::Bind(&ExpireWebHistoryComplete));
1124  }
1125  ExpireHistoryBetween(restrict_urls, begin_time, end_time, callback, tracker);
1126}
1127
1128void HistoryService::BroadcastNotificationsHelper(
1129    int type,
1130    scoped_ptr<history::HistoryDetails> details) {
1131  DCHECK(thread_checker_.CalledOnValidThread());
1132  // TODO(evanm): this is currently necessitated by generate_profile, which
1133  // runs without a browser process. generate_profile should really create
1134  // a browser process, at which point this check can then be nuked.
1135  if (!g_browser_process)
1136    return;
1137
1138  if (!thread_)
1139    return;
1140
1141  // The source of all of our notifications is the profile. Note that this
1142  // pointer is NULL in unit tests.
1143  content::Source<Profile> source(profile_);
1144
1145  // The details object just contains the pointer to the object that the
1146  // backend has allocated for us. The receiver of the notification will cast
1147  // this to the proper type.
1148  content::Details<history::HistoryDetails> det(details.get());
1149
1150  content::NotificationService::current()->Notify(type, source, det);
1151}
1152
1153void HistoryService::OnDBLoaded() {
1154  DCHECK(thread_checker_.CalledOnValidThread());
1155  backend_loaded_ = true;
1156  content::NotificationService::current()->Notify(
1157      chrome::NOTIFICATION_HISTORY_LOADED,
1158      content::Source<Profile>(profile_),
1159      content::Details<HistoryService>(this));
1160}
1161
1162bool HistoryService::GetRowForURL(const GURL& url, history::URLRow* url_row) {
1163  DCHECK(thread_checker_.CalledOnValidThread());
1164  history::URLDatabase* db = InMemoryDatabase();
1165  return db && (db->GetRowForURL(url, url_row) != 0);
1166}
1167
1168void HistoryService::AddVisitDatabaseObserver(
1169    history::VisitDatabaseObserver* observer) {
1170  DCHECK(thread_checker_.CalledOnValidThread());
1171  visit_database_observers_.AddObserver(observer);
1172}
1173
1174void HistoryService::RemoveVisitDatabaseObserver(
1175    history::VisitDatabaseObserver* observer) {
1176  DCHECK(thread_checker_.CalledOnValidThread());
1177  visit_database_observers_.RemoveObserver(observer);
1178}
1179
1180void HistoryService::NotifyVisitDBObserversOnAddVisit(
1181    const history::BriefVisitInfo& info) {
1182  DCHECK(thread_checker_.CalledOnValidThread());
1183  FOR_EACH_OBSERVER(history::VisitDatabaseObserver, visit_database_observers_,
1184                    OnAddVisit(info));
1185}
1186