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