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