history.cc revision 731df977c0511bca2206b5f333555b1205ff1f43
1// Copyright (c) 2010 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.h" 26 27#include "base/callback.h" 28#include "base/message_loop.h" 29#include "base/path_service.h" 30#include "base/ref_counted.h" 31#include "base/string_util.h" 32#include "base/task.h" 33#include "chrome/browser/autocomplete/history_url_provider.h" 34#include "chrome/browser/browser_list.h" 35#include "chrome/browser/browser_process.h" 36#include "chrome/browser/browser_thread.h" 37#include "chrome/browser/browser_window.h" 38#include "chrome/browser/history/download_create_info.h" 39#include "chrome/browser/history/history_backend.h" 40#include "chrome/browser/history/history_notifications.h" 41#include "chrome/browser/history/history_types.h" 42#include "chrome/browser/history/in_memory_database.h" 43#include "chrome/browser/history/in_memory_history_backend.h" 44#include "chrome/browser/history/top_sites.h" 45#include "chrome/browser/prefs/pref_service.h" 46#include "chrome/browser/profile.h" 47#include "chrome/browser/visitedlink_master.h" 48#include "chrome/common/chrome_constants.h" 49#include "chrome/common/notification_service.h" 50#include "chrome/common/pref_names.h" 51#include "chrome/common/thumbnail_score.h" 52#include "chrome/common/url_constants.h" 53#include "grit/chromium_strings.h" 54#include "grit/generated_resources.h" 55#include "third_party/skia/include/core/SkBitmap.h" 56 57using base::Time; 58using history::HistoryBackend; 59 60namespace { 61 62static const char* kHistoryThreadName = "Chrome_HistoryThread"; 63 64} // namespace 65 66// Sends messages from the backend to us on the main thread. This must be a 67// separate class from the history service so that it can hold a reference to 68// the history service (otherwise we would have to manually AddRef and 69// Release when the Backend has a reference to us). 70class HistoryService::BackendDelegate : public HistoryBackend::Delegate { 71 public: 72 explicit BackendDelegate(HistoryService* history_service) 73 : history_service_(history_service), 74 message_loop_(MessageLoop::current()) { 75 } 76 77 virtual void NotifyProfileError(int message_id) { 78 // Send the backend to the history service on the main thread. 79 message_loop_->PostTask(FROM_HERE, NewRunnableMethod(history_service_.get(), 80 &HistoryService::NotifyProfileError, message_id)); 81 } 82 83 virtual void SetInMemoryBackend( 84 history::InMemoryHistoryBackend* backend) { 85 // Send the backend to the history service on the main thread. 86 message_loop_->PostTask(FROM_HERE, NewRunnableMethod(history_service_.get(), 87 &HistoryService::SetInMemoryBackend, backend)); 88 } 89 90 virtual void BroadcastNotifications(NotificationType type, 91 history::HistoryDetails* details) { 92 // Send the notification on the history thread. 93 if (NotificationService::current()) { 94 Details<history::HistoryDetails> det(details); 95 NotificationService::current()->Notify(type, 96 NotificationService::AllSources(), 97 det); 98 } 99 // Send the notification to the history service on the main thread. 100 message_loop_->PostTask(FROM_HERE, NewRunnableMethod(history_service_.get(), 101 &HistoryService::BroadcastNotifications, type, details)); 102 } 103 104 virtual void DBLoaded() { 105 message_loop_->PostTask(FROM_HERE, NewRunnableMethod(history_service_.get(), 106 &HistoryService::OnDBLoaded)); 107 } 108 109 virtual void StartTopSitesMigration() { 110 message_loop_->PostTask(FROM_HERE, NewRunnableMethod(history_service_.get(), 111 &HistoryService::StartTopSitesMigration)); 112 } 113 114 private: 115 scoped_refptr<HistoryService> history_service_; 116 MessageLoop* message_loop_; 117}; 118 119// static 120const history::StarID HistoryService::kBookmarkBarID = 1; 121 122// The history thread is intentionally not a BrowserThread because the 123// sync integration unit tests depend on being able to create more than one 124// history thread. 125HistoryService::HistoryService() 126 : thread_(new base::Thread(kHistoryThreadName)), 127 profile_(NULL), 128 backend_loaded_(false), 129 bookmark_service_(NULL), 130 no_db_(false) { 131 // Is NULL when running generate_profile. 132 if (NotificationService::current()) { 133 registrar_.Add(this, NotificationType::HISTORY_URLS_DELETED, 134 Source<Profile>(profile_)); 135 } 136} 137 138HistoryService::HistoryService(Profile* profile) 139 : thread_(new base::Thread(kHistoryThreadName)), 140 profile_(profile), 141 backend_loaded_(false), 142 bookmark_service_(NULL), 143 no_db_(false) { 144 registrar_.Add(this, NotificationType::HISTORY_URLS_DELETED, 145 Source<Profile>(profile_)); 146} 147 148HistoryService::~HistoryService() { 149 // Shutdown the backend. This does nothing if Cleanup was already invoked. 150 Cleanup(); 151} 152 153bool HistoryService::BackendLoaded() { 154 // NOTE: We start the backend loading even though it completes asynchronously 155 // and thus won't affect the return value of this function. This is because 156 // callers of this assume that if the backend isn't yet loaded it will be 157 // soon, so they will either listen for notifications or just retry this call 158 // later. If we've purged the backend, we haven't necessarily restarted it 159 // loading by now, so we need to trigger the load in order to maintain that 160 // expectation. 161 LoadBackendIfNecessary(); 162 return backend_loaded_; 163} 164 165void HistoryService::UnloadBackend() { 166 if (!history_backend_) 167 return; // Already unloaded. 168 169 // Get rid of the in-memory backend. 170 in_memory_backend_.reset(); 171 172 // The backend's destructor must run on the history thread since it is not 173 // threadsafe. So this thread must not be the last thread holding a reference 174 // to the backend, or a crash could happen. 175 // 176 // We have a reference to the history backend. There is also an extra 177 // reference held by our delegate installed in the backend, which 178 // HistoryBackend::Closing will release. This means if we scheduled a call 179 // to HistoryBackend::Closing and *then* released our backend reference, there 180 // will be a race between us and the backend's Closing function to see who is 181 // the last holder of a reference. If the backend thread's Closing manages to 182 // run before we release our backend refptr, the last reference will be held 183 // by this thread and the destructor will be called from here. 184 // 185 // Therefore, we create a task to run the Closing operation first. This holds 186 // a reference to the backend. Then we release our reference, then we schedule 187 // the task to run. After the task runs, it will delete its reference from 188 // the history thread, ensuring everything works properly. 189 Task* closing_task = 190 NewRunnableMethod(history_backend_.get(), &HistoryBackend::Closing); 191 history_backend_ = NULL; 192 ScheduleTask(PRIORITY_NORMAL, closing_task); 193} 194 195void HistoryService::Cleanup() { 196 if (!thread_) { 197 // We've already cleaned up. 198 return; 199 } 200 201 // Unload the backend. 202 UnloadBackend(); 203 204 // Delete the thread, which joins with the background thread. We defensively 205 // NULL the pointer before deleting it in case somebody tries to use it 206 // during shutdown, but this shouldn't happen. 207 base::Thread* thread = thread_; 208 thread_ = NULL; 209 delete thread; 210} 211 212void HistoryService::NotifyRenderProcessHostDestruction(const void* host) { 213 ScheduleAndForget(PRIORITY_NORMAL, 214 &HistoryBackend::NotifyRenderProcessHostDestruction, host); 215} 216 217history::URLDatabase* HistoryService::InMemoryDatabase() { 218 // NOTE: See comments in BackendLoaded() as to why we call 219 // LoadBackendIfNecessary() here even though it won't affect the return value 220 // for this call. 221 LoadBackendIfNecessary(); 222 if (in_memory_backend_.get()) 223 return in_memory_backend_->db(); 224 return NULL; 225} 226 227history::InMemoryURLIndex* HistoryService::InMemoryIndex() { 228 // NOTE: See comments in BackendLoaded() as to why we call 229 // LoadBackendIfNecessary() here even though it won't affect the return value 230 // for this call. 231 LoadBackendIfNecessary(); 232 if (in_memory_backend_.get()) 233 return in_memory_backend_->InMemoryIndex(); 234 return NULL; 235} 236 237void HistoryService::SetSegmentPresentationIndex(int64 segment_id, int index) { 238 ScheduleAndForget(PRIORITY_UI, 239 &HistoryBackend::SetSegmentPresentationIndex, 240 segment_id, index); 241} 242 243void HistoryService::SetKeywordSearchTermsForURL(const GURL& url, 244 TemplateURLID keyword_id, 245 const string16& term) { 246 ScheduleAndForget(PRIORITY_UI, 247 &HistoryBackend::SetKeywordSearchTermsForURL, 248 url, keyword_id, term); 249} 250 251void HistoryService::DeleteAllSearchTermsForKeyword( 252 TemplateURLID keyword_id) { 253 ScheduleAndForget(PRIORITY_UI, 254 &HistoryBackend::DeleteAllSearchTermsForKeyword, 255 keyword_id); 256} 257 258HistoryService::Handle HistoryService::GetMostRecentKeywordSearchTerms( 259 TemplateURLID keyword_id, 260 const string16& prefix, 261 int max_count, 262 CancelableRequestConsumerBase* consumer, 263 GetMostRecentKeywordSearchTermsCallback* callback) { 264 return Schedule(PRIORITY_UI, &HistoryBackend::GetMostRecentKeywordSearchTerms, 265 consumer, 266 new history::GetMostRecentKeywordSearchTermsRequest(callback), 267 keyword_id, prefix, max_count); 268} 269 270void HistoryService::URLsNoLongerBookmarked(const std::set<GURL>& urls) { 271 ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::URLsNoLongerBookmarked, 272 urls); 273} 274 275HistoryService::Handle HistoryService::ScheduleDBTask( 276 HistoryDBTask* task, 277 CancelableRequestConsumerBase* consumer) { 278 history::HistoryDBTaskRequest* request = new history::HistoryDBTaskRequest( 279 NewCallback(task, &HistoryDBTask::DoneRunOnMainThread)); 280 request->value = task; // The value is the task to execute. 281 return Schedule(PRIORITY_UI, &HistoryBackend::ProcessDBTask, consumer, 282 request); 283} 284 285HistoryService::Handle HistoryService::QuerySegmentUsageSince( 286 CancelableRequestConsumerBase* consumer, 287 const Time from_time, 288 int max_result_count, 289 SegmentQueryCallback* callback) { 290 return Schedule(PRIORITY_UI, &HistoryBackend::QuerySegmentUsage, 291 consumer, new history::QuerySegmentUsageRequest(callback), 292 from_time, max_result_count); 293} 294 295void HistoryService::SetOnBackendDestroyTask(Task* task) { 296 ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::SetOnBackendDestroyTask, 297 MessageLoop::current(), task); 298} 299 300void HistoryService::AddPage(const GURL& url, 301 const void* id_scope, 302 int32 page_id, 303 const GURL& referrer, 304 PageTransition::Type transition, 305 const history::RedirectList& redirects, 306 history::VisitSource visit_source, 307 bool did_replace_entry) { 308 AddPage(url, Time::Now(), id_scope, page_id, referrer, transition, redirects, 309 visit_source, did_replace_entry); 310} 311 312void HistoryService::AddPage(const GURL& url, 313 Time time, 314 const void* id_scope, 315 int32 page_id, 316 const GURL& referrer, 317 PageTransition::Type transition, 318 const history::RedirectList& redirects, 319 history::VisitSource visit_source, 320 bool did_replace_entry) { 321 scoped_refptr<history::HistoryAddPageArgs> request( 322 new history::HistoryAddPageArgs(url, time, id_scope, page_id, referrer, 323 redirects, transition, visit_source, 324 did_replace_entry)); 325 AddPage(*request); 326} 327 328void HistoryService::AddPage(const history::HistoryAddPageArgs& add_page_args) { 329 DCHECK(thread_) << "History service being called after cleanup"; 330 331 // Filter out unwanted URLs. We don't add auto-subframe URLs. They are a 332 // large part of history (think iframes for ads) and we never display them in 333 // history UI. We will still add manual subframes, which are ones the user 334 // has clicked on to get. 335 if (!CanAddURL(add_page_args.url)) 336 return; 337 338 // Add link & all redirects to visited link list. 339 VisitedLinkMaster* visited_links; 340 if (profile_ && (visited_links = profile_->GetVisitedLinkMaster())) { 341 visited_links->AddURL(add_page_args.url); 342 343 if (!add_page_args.redirects.empty()) { 344 // We should not be asked to add a page in the middle of a redirect chain. 345 DCHECK_EQ(add_page_args.url, 346 add_page_args.redirects[add_page_args.redirects.size() - 1]); 347 348 // We need the !redirects.empty() condition above since size_t is unsigned 349 // and will wrap around when we subtract one from a 0 size. 350 for (size_t i = 0; i < add_page_args.redirects.size() - 1; i++) 351 visited_links->AddURL(add_page_args.redirects[i]); 352 } 353 } 354 355 ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::AddPage, 356 scoped_refptr<history::HistoryAddPageArgs>( 357 add_page_args.Clone())); 358} 359 360void HistoryService::SetPageTitle(const GURL& url, 361 const string16& title) { 362 ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::SetPageTitle, url, title); 363} 364 365void HistoryService::AddPageWithDetails(const GURL& url, 366 const string16& title, 367 int visit_count, 368 int typed_count, 369 Time last_visit, 370 bool hidden, 371 history::VisitSource visit_source) { 372 // Filter out unwanted URLs. 373 if (!CanAddURL(url)) 374 return; 375 376 // Add to the visited links system. 377 VisitedLinkMaster* visited_links; 378 if (profile_ && (visited_links = profile_->GetVisitedLinkMaster())) 379 visited_links->AddURL(url); 380 381 history::URLRow row(url); 382 row.set_title(title); 383 row.set_visit_count(visit_count); 384 row.set_typed_count(typed_count); 385 row.set_last_visit(last_visit); 386 row.set_hidden(hidden); 387 388 std::vector<history::URLRow> rows; 389 rows.push_back(row); 390 391 ScheduleAndForget(PRIORITY_NORMAL, 392 &HistoryBackend::AddPagesWithDetails, rows, visit_source); 393} 394 395void HistoryService::AddPagesWithDetails( 396 const std::vector<history::URLRow>& info, 397 history::VisitSource visit_source) { 398 399 // Add to the visited links system. 400 VisitedLinkMaster* visited_links; 401 if (profile_ && (visited_links = profile_->GetVisitedLinkMaster())) { 402 std::vector<GURL> urls; 403 urls.reserve(info.size()); 404 for (std::vector<history::URLRow>::const_iterator i = info.begin(); 405 i != info.end(); 406 ++i) 407 urls.push_back(i->url()); 408 409 visited_links->AddURLs(urls); 410 } 411 412 ScheduleAndForget(PRIORITY_NORMAL, 413 &HistoryBackend::AddPagesWithDetails, info, visit_source); 414} 415 416void HistoryService::SetPageContents(const GURL& url, 417 const string16& contents) { 418 if (!CanAddURL(url)) 419 return; 420 421 ScheduleAndForget(PRIORITY_LOW, &HistoryBackend::SetPageContents, 422 url, contents); 423} 424 425void HistoryService::SetPageThumbnail(const GURL& page_url, 426 const SkBitmap& thumbnail, 427 const ThumbnailScore& score) { 428 if (!CanAddURL(page_url)) 429 return; 430 431 ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::SetPageThumbnail, 432 page_url, thumbnail, score); 433} 434 435HistoryService::Handle HistoryService::GetPageThumbnail( 436 const GURL& page_url, 437 CancelableRequestConsumerBase* consumer, 438 ThumbnailDataCallback* callback) { 439 return Schedule(PRIORITY_NORMAL, &HistoryBackend::GetPageThumbnail, consumer, 440 new history::GetPageThumbnailRequest(callback), page_url); 441} 442 443void HistoryService::GetFavicon(FaviconService::GetFaviconRequest* request, 444 const GURL& icon_url) { 445 Schedule(PRIORITY_NORMAL, &HistoryBackend::GetFavIcon, NULL, request, 446 icon_url); 447} 448 449void HistoryService::UpdateFaviconMappingAndFetch( 450 FaviconService::GetFaviconRequest* request, 451 const GURL& page_url, 452 const GURL& icon_url) { 453 Schedule(PRIORITY_NORMAL, &HistoryBackend::UpdateFavIconMappingAndFetch, NULL, 454 request, page_url, icon_url); 455} 456 457void HistoryService::GetFaviconForURL( 458 FaviconService::GetFaviconRequest* request, 459 const GURL& page_url) { 460 Schedule(PRIORITY_NORMAL, &HistoryBackend::GetFavIconForURL, NULL, request, 461 page_url); 462} 463 464void HistoryService::SetFavicon(const GURL& page_url, 465 const GURL& icon_url, 466 const std::vector<unsigned char>& image_data) { 467 if (!CanAddURL(page_url)) 468 return; 469 470 ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::SetFavIcon, 471 page_url, icon_url, 472 scoped_refptr<RefCountedMemory>(new RefCountedBytes(image_data))); 473} 474 475void HistoryService::SetFaviconOutOfDateForPage(const GURL& page_url) { 476 ScheduleAndForget(PRIORITY_NORMAL, 477 &HistoryBackend::SetFavIconOutOfDateForPage, page_url); 478} 479 480void HistoryService::SetImportedFavicons( 481 const std::vector<history::ImportedFavIconUsage>& favicon_usage) { 482 ScheduleAndForget(PRIORITY_NORMAL, 483 &HistoryBackend::SetImportedFavicons, favicon_usage); 484} 485 486void HistoryService::IterateURLs(URLEnumerator* enumerator) { 487 ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::IterateURLs, enumerator); 488} 489 490HistoryService::Handle HistoryService::QueryURL( 491 const GURL& url, 492 bool want_visits, 493 CancelableRequestConsumerBase* consumer, 494 QueryURLCallback* callback) { 495 return Schedule(PRIORITY_UI, &HistoryBackend::QueryURL, consumer, 496 new history::QueryURLRequest(callback), url, want_visits); 497} 498 499// Downloads ------------------------------------------------------------------- 500 501// Handle creation of a download by creating an entry in the history service's 502// 'downloads' table. 503HistoryService::Handle HistoryService::CreateDownload( 504 const DownloadCreateInfo& create_info, 505 CancelableRequestConsumerBase* consumer, 506 HistoryService::DownloadCreateCallback* callback) { 507 return Schedule(PRIORITY_NORMAL, &HistoryBackend::CreateDownload, consumer, 508 new history::DownloadCreateRequest(callback), create_info); 509} 510 511// Handle queries for a list of all downloads in the history database's 512// 'downloads' table. 513HistoryService::Handle HistoryService::QueryDownloads( 514 CancelableRequestConsumerBase* consumer, 515 DownloadQueryCallback* callback) { 516 return Schedule(PRIORITY_NORMAL, &HistoryBackend::QueryDownloads, consumer, 517 new history::DownloadQueryRequest(callback)); 518} 519 520// Changes all IN_PROGRESS in the database entries to CANCELED. 521// IN_PROGRESS entries are the corrupted entries, not updated by next function 522// because of the crash or some other extremal exit. 523void HistoryService::CleanUpInProgressEntries() { 524 ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::CleanUpInProgressEntries); 525} 526 527// Handle updates for a particular download. This is a 'fire and forget' 528// operation, so we don't need to be called back. 529void HistoryService::UpdateDownload(int64 received_bytes, 530 int32 state, 531 int64 db_handle) { 532 ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::UpdateDownload, 533 received_bytes, state, db_handle); 534} 535 536void HistoryService::UpdateDownloadPath(const FilePath& path, 537 int64 db_handle) { 538 ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::UpdateDownloadPath, 539 path, db_handle); 540} 541 542void HistoryService::RemoveDownload(int64 db_handle) { 543 ScheduleAndForget(PRIORITY_NORMAL, 544 &HistoryBackend::RemoveDownload, db_handle); 545} 546 547void HistoryService::RemoveDownloadsBetween(Time remove_begin, 548 Time remove_end) { 549 ScheduleAndForget(PRIORITY_NORMAL, 550 &HistoryBackend::RemoveDownloadsBetween, 551 remove_begin, 552 remove_end); 553} 554 555HistoryService::Handle HistoryService::QueryHistory( 556 const string16& text_query, 557 const history::QueryOptions& options, 558 CancelableRequestConsumerBase* consumer, 559 QueryHistoryCallback* callback) { 560 return Schedule(PRIORITY_UI, &HistoryBackend::QueryHistory, consumer, 561 new history::QueryHistoryRequest(callback), 562 text_query, options); 563} 564 565HistoryService::Handle HistoryService::QueryRedirectsFrom( 566 const GURL& from_url, 567 CancelableRequestConsumerBase* consumer, 568 QueryRedirectsCallback* callback) { 569 return Schedule(PRIORITY_UI, &HistoryBackend::QueryRedirectsFrom, consumer, 570 new history::QueryRedirectsRequest(callback), from_url); 571} 572 573HistoryService::Handle HistoryService::QueryRedirectsTo( 574 const GURL& to_url, 575 CancelableRequestConsumerBase* consumer, 576 QueryRedirectsCallback* callback) { 577 return Schedule(PRIORITY_NORMAL, &HistoryBackend::QueryRedirectsTo, consumer, 578 new history::QueryRedirectsRequest(callback), to_url); 579} 580 581HistoryService::Handle HistoryService::GetVisitCountToHost( 582 const GURL& url, 583 CancelableRequestConsumerBase* consumer, 584 GetVisitCountToHostCallback* callback) { 585 return Schedule(PRIORITY_UI, &HistoryBackend::GetVisitCountToHost, consumer, 586 new history::GetVisitCountToHostRequest(callback), url); 587} 588 589HistoryService::Handle HistoryService::QueryTopURLsAndRedirects( 590 int result_count, 591 CancelableRequestConsumerBase* consumer, 592 QueryTopURLsAndRedirectsCallback* callback) { 593 return Schedule(PRIORITY_NORMAL, &HistoryBackend::QueryTopURLsAndRedirects, 594 consumer, new history::QueryTopURLsAndRedirectsRequest(callback), 595 result_count); 596} 597 598HistoryService::Handle HistoryService::QueryMostVisitedURLs( 599 int result_count, 600 int days_back, 601 CancelableRequestConsumerBase* consumer, 602 QueryMostVisitedURLsCallback* callback) { 603 return Schedule(PRIORITY_NORMAL, &HistoryBackend::QueryMostVisitedURLs, 604 consumer, 605 new history::QueryMostVisitedURLsRequest(callback), 606 result_count, days_back); 607} 608 609void HistoryService::Observe(NotificationType type, 610 const NotificationSource& source, 611 const NotificationDetails& details) { 612 if (type != NotificationType::HISTORY_URLS_DELETED) { 613 NOTREACHED(); 614 return; 615 } 616 617 // Update the visited link system for deleted URLs. We will update the 618 // visited link system for added URLs as soon as we get the add 619 // notification (we don't have to wait for the backend, which allows us to 620 // be faster to update the state). 621 // 622 // For deleted URLs, we don't typically know what will be deleted since 623 // delete notifications are by time. We would also like to be more 624 // respectful of privacy and never tell the user something is gone when it 625 // isn't. Therefore, we update the delete URLs after the fact. 626 if (!profile_) 627 return; // No profile, probably unit testing. 628 Details<history::URLsDeletedDetails> deleted_details(details); 629 VisitedLinkMaster* visited_links = profile_->GetVisitedLinkMaster(); 630 if (!visited_links) 631 return; // Nobody to update. 632 if (deleted_details->all_history) 633 visited_links->DeleteAllURLs(); 634 else // Delete individual ones. 635 visited_links->DeleteURLs(deleted_details->urls); 636} 637 638bool HistoryService::Init(const FilePath& history_dir, 639 BookmarkService* bookmark_service, 640 bool no_db) { 641 if (!thread_->Start()) { 642 Cleanup(); 643 return false; 644 } 645 646 history_dir_ = history_dir; 647 bookmark_service_ = bookmark_service; 648 no_db_ = no_db; 649 650 // Create the history backend. 651 LoadBackendIfNecessary(); 652 return true; 653} 654 655void HistoryService::ScheduleAutocomplete(HistoryURLProvider* provider, 656 HistoryURLProviderParams* params) { 657 ScheduleAndForget(PRIORITY_UI, &HistoryBackend::ScheduleAutocomplete, 658 scoped_refptr<HistoryURLProvider>(provider), params); 659} 660 661void HistoryService::ScheduleTask(SchedulePriority priority, 662 Task* task) { 663 // TODO(brettw): do prioritization. 664 thread_->message_loop()->PostTask(FROM_HERE, task); 665} 666 667// static 668bool HistoryService::CanAddURL(const GURL& url) { 669 if (!url.is_valid()) 670 return false; 671 672 // TODO: We should allow kChromeUIScheme URLs if they have been explicitly 673 // typed. Right now, however, these are marked as typed even when triggered 674 // by a shortcut or menu action. 675 if (url.SchemeIs(chrome::kJavaScriptScheme) || 676 url.SchemeIs(chrome::kChromeUIScheme) || 677 url.SchemeIs(chrome::kViewSourceScheme) || 678 url.SchemeIs(chrome::kChromeInternalScheme)) 679 return false; 680 681 if (url.SchemeIs(chrome::kAboutScheme)) { 682 if (LowerCaseEqualsASCII(url.path(), "blank")) 683 return false; 684 // We allow all other about URLs since the user may like to see things 685 // like "about:memory" or "about:histograms" in their history and 686 // autocomplete. 687 } 688 689 return true; 690} 691 692void HistoryService::SetInMemoryBackend( 693 history::InMemoryHistoryBackend* mem_backend) { 694 DCHECK(!in_memory_backend_.get()) << "Setting mem DB twice"; 695 in_memory_backend_.reset(mem_backend); 696 697 // The database requires additional initialization once we own it. 698 in_memory_backend_->AttachToHistoryService(profile_); 699} 700 701void HistoryService::NotifyProfileError(int message_id) { 702 Source<HistoryService> source(this); 703 NotificationService::current()->Notify(NotificationType::PROFILE_ERROR, 704 source, Details<int>(&message_id)); 705} 706 707void HistoryService::DeleteURL(const GURL& url) { 708 // We will update the visited links when we observe the delete notifications. 709 ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::DeleteURL, url); 710} 711 712void HistoryService::ExpireHistoryBetween( 713 const std::set<GURL>& restrict_urls, 714 Time begin_time, Time end_time, 715 CancelableRequestConsumerBase* consumer, 716 ExpireHistoryCallback* callback) { 717 718 // We will update the visited links when we observe the delete notifications. 719 Schedule(PRIORITY_UI, &HistoryBackend::ExpireHistoryBetween, consumer, 720 new history::ExpireHistoryRequest(callback), 721 restrict_urls, begin_time, end_time); 722} 723 724void HistoryService::BroadcastNotifications( 725 NotificationType type, 726 history::HistoryDetails* details_deleted) { 727 // We take ownership of the passed-in pointer and delete it. It was made for 728 // us on another thread, so the caller doesn't know when we will handle it. 729 scoped_ptr<history::HistoryDetails> details(details_deleted); 730 // TODO(evanm): this is currently necessitated by generate_profile, which 731 // runs without a browser process. generate_profile should really create 732 // a browser process, at which point this check can then be nuked. 733 if (!g_browser_process) 734 return; 735 736 // The source of all of our notifications is the profile. Note that this 737 // pointer is NULL in unit tests. 738 Source<Profile> source(profile_); 739 740 // The details object just contains the pointer to the object that the 741 // backend has allocated for us. The receiver of the notification will cast 742 // this to the proper type. 743 Details<history::HistoryDetails> det(details_deleted); 744 745 NotificationService::current()->Notify(type, source, det); 746} 747 748void HistoryService::LoadBackendIfNecessary() { 749 if (!thread_ || history_backend_) 750 return; // Failed to init, or already started loading. 751 752 scoped_refptr<HistoryBackend> backend( 753 new HistoryBackend(history_dir_, 754 new BackendDelegate(this), 755 bookmark_service_)); 756 history_backend_.swap(backend); 757 758 // There may not be a profile when unit testing. 759 std::string languages; 760 if (profile_) { 761 PrefService* prefs = profile_->GetPrefs(); 762 languages = prefs->GetString(prefs::kAcceptLanguages); 763 } 764 ScheduleAndForget(PRIORITY_UI, &HistoryBackend::Init, languages, no_db_); 765} 766 767void HistoryService::OnDBLoaded() { 768 backend_loaded_ = true; 769 NotificationService::current()->Notify(NotificationType::HISTORY_LOADED, 770 Source<Profile>(profile_), 771 Details<HistoryService>(this)); 772} 773 774void HistoryService::StartTopSitesMigration() { 775 if (history::TopSites::IsEnabled()) { 776 history::TopSites* ts = profile_->GetTopSites(); 777 ts->StartMigration(); 778 } 779} 780 781void HistoryService::OnTopSitesReady() { 782 ScheduleAndForget(PRIORITY_NORMAL, 783 &HistoryBackend::MigrateThumbnailsDatabase); 784} 785