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