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