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