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