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