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