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