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