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