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