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