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