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