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