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