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