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