Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / history / history_service.cc
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
64 using base::Time;
65 using history::HistoryBackend;
66 using history::KeywordID;
67
68 namespace {
69
70 static const char* kHistoryThreadName = "Chrome_HistoryThread";
71
72 void RunWithFaviconResults(
73     const favicon_base::FaviconResultsCallback& callback,
74     std::vector<favicon_base::FaviconRawBitmapResult>* bitmap_results) {
75   callback.Run(*bitmap_results);
76 }
77
78 void RunWithFaviconResult(
79     const favicon_base::FaviconRawBitmapCallback& callback,
80     favicon_base::FaviconRawBitmapResult* bitmap_result) {
81   callback.Run(*bitmap_result);
82 }
83
84 void RunWithQueryURLResult(const HistoryService::QueryURLCallback& callback,
85                            const history::QueryURLResult* result) {
86   callback.Run(result->success, result->row, result->visits);
87 }
88
89 void 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.
96 class 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().
120 void 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).
133 class 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.
208 HistoryService::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
217 HistoryService::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
231 HistoryService::~HistoryService() {
232   DCHECK(thread_checker_.CalledOnValidThread());
233   // Shutdown the backend. This does nothing if Cleanup was already invoked.
234   Cleanup();
235 }
236
237 bool HistoryService::BackendLoaded() {
238   DCHECK(thread_checker_.CalledOnValidThread());
239   return backend_loaded_;
240 }
241
242 void 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
250 history::URLDatabase* HistoryService::InMemoryDatabase() {
251   DCHECK(thread_checker_.CalledOnValidThread());
252   return in_memory_backend_ ? in_memory_backend_->db() : NULL;
253 }
254
255 bool 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
264 bool 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
274 bool 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
283 history::TypedUrlSyncableService* HistoryService::GetTypedUrlSyncableService()
284     const {
285   return history_backend_->GetTypedUrlSyncableService();
286 }
287
288 void HistoryService::Shutdown() {
289   DCHECK(thread_checker_.CalledOnValidThread());
290   Cleanup();
291 }
292
293 void 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
303 void 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
315 void 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
322 void 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
330 void 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
337 void 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
355 void HistoryService::FlushForTest(const base::Closure& flushed) {
356   thread_->message_loop_proxy()->PostTaskAndReply(
357       FROM_HERE, base::Bind(&base::DoNothing), flushed);
358 }
359
360 void 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
367 void 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
383 void 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
394 void 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
424 void 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
435 void 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
442 void 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
452 void 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
483 void 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
502 base::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
524 base::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
546 base::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
568 base::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
588 base::CancelableTaskTracker::TaskId
589 HistoryService::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
613 void 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
628 void 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
642 void 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
649 void 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
657 void 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
665 base::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.
689 void 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
702 void 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.
715 void 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.
734 void 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
740 void 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
747 base::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
766 base::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
783 base::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
799 base::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
819 base::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
838 base::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
859 void 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
916 void 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
952 void 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
959 bool 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
1006 void 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
1013 void 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
1023 bool 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
1047 base::WeakPtr<HistoryService> HistoryService::AsWeakPtr() {
1048   DCHECK(thread_checker_.CalledOnValidThread());
1049   return weak_ptr_factory_.GetWeakPtr();
1050 }
1051
1052 syncer::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
1064 void 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
1070 syncer::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
1078 syncer::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
1085 syncer::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
1092 void 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
1102 void HistoryService::NotifyProfileError(sql::InitStatus init_status) {
1103   DCHECK(thread_checker_.CalledOnValidThread());
1104   if (history_client_)
1105     history_client_->NotifyProfileError(init_status);
1106 }
1107
1108 void 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
1115 void 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
1123 void 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
1141 void 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
1154 void 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
1184 void 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
1209 void 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
1218 bool 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
1224 void HistoryService::AddVisitDatabaseObserver(
1225     history::VisitDatabaseObserver* observer) {
1226   DCHECK(thread_checker_.CalledOnValidThread());
1227   visit_database_observers_.AddObserver(observer);
1228 }
1229
1230 void HistoryService::RemoveVisitDatabaseObserver(
1231     history::VisitDatabaseObserver* observer) {
1232   DCHECK(thread_checker_.CalledOnValidThread());
1233   visit_database_observers_.RemoveObserver(observer);
1234 }
1235
1236 void 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
1243 scoped_ptr<base::CallbackList<void(const std::set<GURL>&)>::Subscription>
1244 HistoryService::AddFaviconChangedCallback(
1245     const HistoryService::OnFaviconChangedCallback& callback) {
1246   DCHECK(thread_checker_.CalledOnValidThread());
1247   return favicon_changed_callback_list_.Add(callback);
1248 }
1249
1250 void HistoryService::NotifyFaviconChanged(
1251     const std::set<GURL>& changed_favicons) {
1252   DCHECK(thread_checker_.CalledOnValidThread());
1253   favicon_changed_callback_list_.Notify(changed_favicons);
1254 }