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