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