1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 // The history system runs on a background thread so that potentially slow 6 // database operations don't delay the browser. This backend processing is 7 // represented by HistoryBackend. The HistoryService's job is to dispatch to 8 // that thread. 9 // 10 // Main thread History thread 11 // ----------- -------------- 12 // HistoryService <----------------> HistoryBackend 13 // -> HistoryDatabase 14 // -> SQLite connection to History 15 // -> ArchivedDatabase 16 // -> SQLite connection to Archived History 17 // -> ThumbnailDatabase 18 // -> SQLite connection to Thumbnails 19 // (and favicons) 20 21 #include "chrome/browser/history/history_service.h" 22 23 #include "base/bind_helpers.h" 24 #include "base/callback.h" 25 #include "base/command_line.h" 26 #include "base/compiler_specific.h" 27 #include "base/location.h" 28 #include "base/memory/ref_counted.h" 29 #include "base/message_loop/message_loop.h" 30 #include "base/path_service.h" 31 #include "base/prefs/pref_service.h" 32 #include "base/thread_task_runner_handle.h" 33 #include "base/threading/thread.h" 34 #include "base/time/time.h" 35 #include "chrome/browser/autocomplete/history_url_provider.h" 36 #include "chrome/browser/bookmarks/bookmark_model.h" 37 #include "chrome/browser/bookmarks/bookmark_model_factory.h" 38 #include "chrome/browser/browser_process.h" 39 #include "chrome/browser/chrome_notification_types.h" 40 #include "chrome/browser/history/download_row.h" 41 #include "chrome/browser/history/history_backend.h" 42 #include "chrome/browser/history/history_notifications.h" 43 #include "chrome/browser/history/history_types.h" 44 #include "chrome/browser/history/in_memory_database.h" 45 #include "chrome/browser/history/in_memory_history_backend.h" 46 #include "chrome/browser/history/in_memory_url_index.h" 47 #include "chrome/browser/history/top_sites.h" 48 #include "chrome/browser/history/visit_database.h" 49 #include "chrome/browser/history/visit_filter.h" 50 #include "chrome/browser/history/web_history_service.h" 51 #include "chrome/browser/history/web_history_service_factory.h" 52 #include "chrome/browser/profiles/profile.h" 53 #include "chrome/browser/ui/profile_error_dialog.h" 54 #include "chrome/common/chrome_constants.h" 55 #include "chrome/common/chrome_switches.h" 56 #include "chrome/common/importer/imported_favicon_usage.h" 57 #include "chrome/common/pref_names.h" 58 #include "chrome/common/thumbnail_score.h" 59 #include "chrome/common/url_constants.h" 60 #include "components/visitedlink/browser/visitedlink_master.h" 61 #include "content/public/browser/browser_thread.h" 62 #include "content/public/browser/download_item.h" 63 #include "content/public/browser/notification_service.h" 64 #include "grit/chromium_strings.h" 65 #include "grit/generated_resources.h" 66 #include "sync/api/sync_error_factory.h" 67 #include "third_party/skia/include/core/SkBitmap.h" 68 69 using base::Time; 70 using history::HistoryBackend; 71 72 namespace { 73 74 static const char* kHistoryThreadName = "Chrome_HistoryThread"; 75 76 template<typename PODType> void DerefPODType( 77 const base::Callback<void(PODType)>& callback, PODType* pod_value) { 78 callback.Run(*pod_value); 79 } 80 81 void RunWithFaviconResults( 82 const FaviconService::FaviconResultsCallback& callback, 83 std::vector<chrome::FaviconBitmapResult>* bitmap_results) { 84 callback.Run(*bitmap_results); 85 } 86 87 void 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. 94 class 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(). 118 void 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). 131 class 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. 201 HistoryService::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 211 HistoryService::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 228 HistoryService::~HistoryService() { 229 DCHECK(thread_checker_.CalledOnValidThread()); 230 // Shutdown the backend. This does nothing if Cleanup was already invoked. 231 Cleanup(); 232 } 233 234 bool 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 247 void 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 289 void 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 309 void HistoryService::NotifyRenderProcessHostDestruction(const void* host) { 310 DCHECK(thread_checker_.CalledOnValidThread()); 311 ScheduleAndForget(PRIORITY_NORMAL, 312 &HistoryBackend::NotifyRenderProcessHostDestruction, host); 313 } 314 315 history::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 326 bool 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 335 bool 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 345 bool 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 354 history::TypedUrlSyncableService* HistoryService::GetTypedUrlSyncableService() 355 const { 356 return history_backend_->GetTypedUrlSyncableService(); 357 } 358 359 void 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 377 void HistoryService::SetKeywordSearchTermsForURL(const GURL& url, 378 TemplateURLID keyword_id, 379 const base::string16& term) { 380 DCHECK(thread_checker_.CalledOnValidThread()); 381 ScheduleAndForget(PRIORITY_UI, 382 &HistoryBackend::SetKeywordSearchTermsForURL, 383 url, keyword_id, term); 384 } 385 386 void HistoryService::DeleteAllSearchTermsForKeyword( 387 TemplateURLID keyword_id) { 388 DCHECK(thread_checker_.CalledOnValidThread()); 389 ScheduleAndForget(PRIORITY_UI, 390 &HistoryBackend::DeleteAllSearchTermsForKeyword, 391 keyword_id); 392 } 393 394 HistoryService::Handle HistoryService::GetMostRecentKeywordSearchTerms( 395 TemplateURLID keyword_id, 396 const base::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 407 void HistoryService::DeleteKeywordSearchTermForURL(const GURL& url) { 408 DCHECK(thread_checker_.CalledOnValidThread()); 409 ScheduleAndForget(PRIORITY_UI, &HistoryBackend::DeleteKeywordSearchTermForURL, 410 url); 411 } 412 413 void HistoryService::DeleteMatchingURLsForKeyword(TemplateURLID keyword_id, 414 const base::string16& term) { 415 DCHECK(thread_checker_.CalledOnValidThread()); 416 ScheduleAndForget(PRIORITY_UI, &HistoryBackend::DeleteMatchingURLsForKeyword, 417 keyword_id, term); 418 } 419 420 void HistoryService::URLsNoLongerBookmarked(const std::set<GURL>& urls) { 421 DCHECK(thread_checker_.CalledOnValidThread()); 422 ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::URLsNoLongerBookmarked, 423 urls); 424 } 425 426 void HistoryService::ScheduleDBTask(history::HistoryDBTask* task, 427 CancelableRequestConsumerBase* consumer) { 428 DCHECK(thread_checker_.CalledOnValidThread()); 429 history::HistoryDBTaskRequest* request = new history::HistoryDBTaskRequest( 430 base::Bind(&history::HistoryDBTask::DoneRunOnMainThread, task)); 431 request->value = task; // The value is the task to execute. 432 Schedule(PRIORITY_UI, &HistoryBackend::ProcessDBTask, consumer, request); 433 } 434 435 HistoryService::Handle HistoryService::QuerySegmentUsageSince( 436 CancelableRequestConsumerBase* consumer, 437 const Time from_time, 438 int max_result_count, 439 const SegmentQueryCallback& callback) { 440 DCHECK(thread_checker_.CalledOnValidThread()); 441 return Schedule(PRIORITY_UI, &HistoryBackend::QuerySegmentUsage, 442 consumer, new history::QuerySegmentUsageRequest(callback), 443 from_time, max_result_count); 444 } 445 446 void HistoryService::IncreaseSegmentDuration(const GURL& url, 447 Time time, 448 base::TimeDelta delta) { 449 DCHECK(thread_checker_.CalledOnValidThread()); 450 ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::IncreaseSegmentDuration, 451 url, time, delta); 452 } 453 454 HistoryService::Handle HistoryService::QuerySegmentDurationSince( 455 CancelableRequestConsumerBase* consumer, 456 base::Time from_time, 457 int max_result_count, 458 const SegmentQueryCallback& callback) { 459 DCHECK(thread_checker_.CalledOnValidThread()); 460 return Schedule(PRIORITY_UI, &HistoryBackend::QuerySegmentDuration, 461 consumer, new history::QuerySegmentUsageRequest(callback), 462 from_time, max_result_count); 463 } 464 465 void HistoryService::FlushForTest(const base::Closure& flushed) { 466 thread_->message_loop_proxy()->PostTaskAndReply( 467 FROM_HERE, base::Bind(&base::DoNothing), flushed); 468 } 469 470 void HistoryService::SetOnBackendDestroyTask(const base::Closure& task) { 471 DCHECK(thread_checker_.CalledOnValidThread()); 472 ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::SetOnBackendDestroyTask, 473 base::MessageLoop::current(), task); 474 } 475 476 void HistoryService::AddPage(const GURL& url, 477 Time time, 478 const void* id_scope, 479 int32 page_id, 480 const GURL& referrer, 481 const history::RedirectList& redirects, 482 content::PageTransition transition, 483 history::VisitSource visit_source, 484 bool did_replace_entry) { 485 DCHECK(thread_checker_.CalledOnValidThread()); 486 AddPage( 487 history::HistoryAddPageArgs(url, time, id_scope, page_id, referrer, 488 redirects, transition, visit_source, 489 did_replace_entry)); 490 } 491 492 void HistoryService::AddPage(const GURL& url, 493 base::Time time, 494 history::VisitSource visit_source) { 495 DCHECK(thread_checker_.CalledOnValidThread()); 496 AddPage( 497 history::HistoryAddPageArgs(url, time, NULL, 0, GURL(), 498 history::RedirectList(), 499 content::PAGE_TRANSITION_LINK, 500 visit_source, false)); 501 } 502 503 void HistoryService::AddPage(const history::HistoryAddPageArgs& add_page_args) { 504 DCHECK(thread_checker_.CalledOnValidThread()); 505 DCHECK(thread_) << "History service being called after cleanup"; 506 507 // Filter out unwanted URLs. We don't add auto-subframe URLs. They are a 508 // large part of history (think iframes for ads) and we never display them in 509 // history UI. We will still add manual subframes, which are ones the user 510 // has clicked on to get. 511 if (!CanAddURL(add_page_args.url)) 512 return; 513 514 // Add link & all redirects to visited link list. 515 if (visitedlink_master_) { 516 visitedlink_master_->AddURL(add_page_args.url); 517 518 if (!add_page_args.redirects.empty()) { 519 // We should not be asked to add a page in the middle of a redirect chain. 520 DCHECK_EQ(add_page_args.url, 521 add_page_args.redirects[add_page_args.redirects.size() - 1]); 522 523 // We need the !redirects.empty() condition above since size_t is unsigned 524 // and will wrap around when we subtract one from a 0 size. 525 for (size_t i = 0; i < add_page_args.redirects.size() - 1; i++) 526 visitedlink_master_->AddURL(add_page_args.redirects[i]); 527 } 528 } 529 530 ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::AddPage, add_page_args); 531 } 532 533 void HistoryService::AddPageNoVisitForBookmark(const GURL& url, 534 const base::string16& title) { 535 DCHECK(thread_checker_.CalledOnValidThread()); 536 if (!CanAddURL(url)) 537 return; 538 539 ScheduleAndForget(PRIORITY_NORMAL, 540 &HistoryBackend::AddPageNoVisitForBookmark, url, title); 541 } 542 543 void HistoryService::SetPageTitle(const GURL& url, 544 const base::string16& title) { 545 DCHECK(thread_checker_.CalledOnValidThread()); 546 ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::SetPageTitle, url, title); 547 } 548 549 void HistoryService::UpdateWithPageEndTime(const void* host, 550 int32 page_id, 551 const GURL& url, 552 Time end_ts) { 553 DCHECK(thread_checker_.CalledOnValidThread()); 554 ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::UpdateWithPageEndTime, 555 host, page_id, url, end_ts); 556 } 557 558 void HistoryService::AddPageWithDetails(const GURL& url, 559 const base::string16& title, 560 int visit_count, 561 int typed_count, 562 Time last_visit, 563 bool hidden, 564 history::VisitSource visit_source) { 565 DCHECK(thread_checker_.CalledOnValidThread()); 566 // Filter out unwanted URLs. 567 if (!CanAddURL(url)) 568 return; 569 570 // Add to the visited links system. 571 if (visitedlink_master_) 572 visitedlink_master_->AddURL(url); 573 574 history::URLRow row(url); 575 row.set_title(title); 576 row.set_visit_count(visit_count); 577 row.set_typed_count(typed_count); 578 row.set_last_visit(last_visit); 579 row.set_hidden(hidden); 580 581 history::URLRows rows; 582 rows.push_back(row); 583 584 ScheduleAndForget(PRIORITY_NORMAL, 585 &HistoryBackend::AddPagesWithDetails, rows, visit_source); 586 } 587 588 void HistoryService::AddPagesWithDetails(const history::URLRows& info, 589 history::VisitSource visit_source) { 590 DCHECK(thread_checker_.CalledOnValidThread()); 591 // Add to the visited links system. 592 if (visitedlink_master_) { 593 std::vector<GURL> urls; 594 urls.reserve(info.size()); 595 for (history::URLRows::const_iterator i = info.begin(); i != info.end(); 596 ++i) 597 urls.push_back(i->url()); 598 599 visitedlink_master_->AddURLs(urls); 600 } 601 602 ScheduleAndForget(PRIORITY_NORMAL, 603 &HistoryBackend::AddPagesWithDetails, info, visit_source); 604 } 605 606 CancelableTaskTracker::TaskId HistoryService::GetFavicons( 607 const std::vector<GURL>& icon_urls, 608 int icon_types, 609 int desired_size_in_dip, 610 const std::vector<ui::ScaleFactor>& desired_scale_factors, 611 const FaviconService::FaviconResultsCallback& callback, 612 CancelableTaskTracker* tracker) { 613 DCHECK(thread_checker_.CalledOnValidThread()); 614 LoadBackendIfNecessary(); 615 616 std::vector<chrome::FaviconBitmapResult>* results = 617 new std::vector<chrome::FaviconBitmapResult>(); 618 return tracker->PostTaskAndReply( 619 thread_->message_loop_proxy().get(), 620 FROM_HERE, 621 base::Bind(&HistoryBackend::GetFavicons, 622 history_backend_.get(), 623 icon_urls, 624 icon_types, 625 desired_size_in_dip, 626 desired_scale_factors, 627 results), 628 base::Bind(&RunWithFaviconResults, callback, base::Owned(results))); 629 } 630 631 CancelableTaskTracker::TaskId HistoryService::GetFaviconsForURL( 632 const GURL& page_url, 633 int icon_types, 634 int desired_size_in_dip, 635 const std::vector<ui::ScaleFactor>& desired_scale_factors, 636 const FaviconService::FaviconResultsCallback& callback, 637 CancelableTaskTracker* tracker) { 638 DCHECK(thread_checker_.CalledOnValidThread()); 639 LoadBackendIfNecessary(); 640 641 std::vector<chrome::FaviconBitmapResult>* results = 642 new std::vector<chrome::FaviconBitmapResult>(); 643 return tracker->PostTaskAndReply( 644 thread_->message_loop_proxy().get(), 645 FROM_HERE, 646 base::Bind(&HistoryBackend::GetFaviconsForURL, 647 history_backend_.get(), 648 page_url, 649 icon_types, 650 desired_size_in_dip, 651 desired_scale_factors, 652 results), 653 base::Bind(&RunWithFaviconResults, callback, base::Owned(results))); 654 } 655 656 CancelableTaskTracker::TaskId HistoryService::GetLargestFaviconForURL( 657 const GURL& page_url, 658 const std::vector<int>& icon_types, 659 int minimum_size_in_pixels, 660 const FaviconService::FaviconRawCallback& callback, 661 CancelableTaskTracker* tracker) { 662 DCHECK(thread_checker_.CalledOnValidThread()); 663 LoadBackendIfNecessary(); 664 665 chrome::FaviconBitmapResult* result = new chrome::FaviconBitmapResult(); 666 return tracker->PostTaskAndReply( 667 thread_->message_loop_proxy().get(), 668 FROM_HERE, 669 base::Bind(&HistoryBackend::GetLargestFaviconForURL, 670 history_backend_.get(), 671 page_url, 672 icon_types, 673 minimum_size_in_pixels, 674 result), 675 base::Bind(&RunWithFaviconResult, callback, base::Owned(result))); 676 } 677 678 CancelableTaskTracker::TaskId HistoryService::GetFaviconForID( 679 chrome::FaviconID favicon_id, 680 int desired_size_in_dip, 681 ui::ScaleFactor desired_scale_factor, 682 const FaviconService::FaviconResultsCallback& callback, 683 CancelableTaskTracker* tracker) { 684 DCHECK(thread_checker_.CalledOnValidThread()); 685 LoadBackendIfNecessary(); 686 687 std::vector<chrome::FaviconBitmapResult>* results = 688 new std::vector<chrome::FaviconBitmapResult>(); 689 return tracker->PostTaskAndReply( 690 thread_->message_loop_proxy().get(), 691 FROM_HERE, 692 base::Bind(&HistoryBackend::GetFaviconForID, 693 history_backend_.get(), 694 favicon_id, 695 desired_size_in_dip, 696 desired_scale_factor, 697 results), 698 base::Bind(&RunWithFaviconResults, callback, base::Owned(results))); 699 } 700 701 CancelableTaskTracker::TaskId HistoryService::UpdateFaviconMappingsAndFetch( 702 const GURL& page_url, 703 const std::vector<GURL>& icon_urls, 704 int icon_types, 705 int desired_size_in_dip, 706 const std::vector<ui::ScaleFactor>& desired_scale_factors, 707 const FaviconService::FaviconResultsCallback& callback, 708 CancelableTaskTracker* tracker) { 709 DCHECK(thread_checker_.CalledOnValidThread()); 710 LoadBackendIfNecessary(); 711 712 std::vector<chrome::FaviconBitmapResult>* results = 713 new std::vector<chrome::FaviconBitmapResult>(); 714 return tracker->PostTaskAndReply( 715 thread_->message_loop_proxy().get(), 716 FROM_HERE, 717 base::Bind(&HistoryBackend::UpdateFaviconMappingsAndFetch, 718 history_backend_.get(), 719 page_url, 720 icon_urls, 721 icon_types, 722 desired_size_in_dip, 723 desired_scale_factors, 724 results), 725 base::Bind(&RunWithFaviconResults, callback, base::Owned(results))); 726 } 727 728 void HistoryService::MergeFavicon( 729 const GURL& page_url, 730 const GURL& icon_url, 731 chrome::IconType icon_type, 732 scoped_refptr<base::RefCountedMemory> bitmap_data, 733 const gfx::Size& pixel_size) { 734 DCHECK(thread_checker_.CalledOnValidThread()); 735 if (!CanAddURL(page_url)) 736 return; 737 738 ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::MergeFavicon, page_url, 739 icon_url, icon_type, bitmap_data, pixel_size); 740 } 741 742 void HistoryService::SetFavicons( 743 const GURL& page_url, 744 chrome::IconType icon_type, 745 const std::vector<chrome::FaviconBitmapData>& favicon_bitmap_data) { 746 DCHECK(thread_checker_.CalledOnValidThread()); 747 if (!CanAddURL(page_url)) 748 return; 749 750 ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::SetFavicons, page_url, 751 icon_type, favicon_bitmap_data); 752 } 753 754 void HistoryService::SetFaviconsOutOfDateForPage(const GURL& page_url) { 755 DCHECK(thread_checker_.CalledOnValidThread()); 756 ScheduleAndForget(PRIORITY_NORMAL, 757 &HistoryBackend::SetFaviconsOutOfDateForPage, page_url); 758 } 759 760 void HistoryService::CloneFavicons(const GURL& old_page_url, 761 const GURL& new_page_url) { 762 DCHECK(thread_checker_.CalledOnValidThread()); 763 ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::CloneFavicons, 764 old_page_url, new_page_url); 765 } 766 767 void HistoryService::SetImportedFavicons( 768 const std::vector<ImportedFaviconUsage>& favicon_usage) { 769 DCHECK(thread_checker_.CalledOnValidThread()); 770 ScheduleAndForget(PRIORITY_NORMAL, 771 &HistoryBackend::SetImportedFavicons, favicon_usage); 772 } 773 774 HistoryService::Handle HistoryService::QueryURL( 775 const GURL& url, 776 bool want_visits, 777 CancelableRequestConsumerBase* consumer, 778 const QueryURLCallback& callback) { 779 DCHECK(thread_checker_.CalledOnValidThread()); 780 return Schedule(PRIORITY_UI, &HistoryBackend::QueryURL, consumer, 781 new history::QueryURLRequest(callback), url, want_visits); 782 } 783 784 // Downloads ------------------------------------------------------------------- 785 786 // Handle creation of a download by creating an entry in the history service's 787 // 'downloads' table. 788 void HistoryService::CreateDownload( 789 const history::DownloadRow& create_info, 790 const HistoryService::DownloadCreateCallback& callback) { 791 DCHECK(thread_) << "History service being called after cleanup"; 792 DCHECK(thread_checker_.CalledOnValidThread()); 793 LoadBackendIfNecessary(); 794 bool* success = new bool(false); 795 thread_->message_loop_proxy()->PostTaskAndReply( 796 FROM_HERE, 797 base::Bind(&HistoryBackend::CreateDownload, 798 history_backend_.get(), 799 create_info, 800 success), 801 base::Bind(&DerefPODType<bool>, callback, base::Owned(success))); 802 } 803 804 void HistoryService::GetNextDownloadId( 805 const content::DownloadIdCallback& callback) { 806 DCHECK(thread_) << "History service being called after cleanup"; 807 DCHECK(thread_checker_.CalledOnValidThread()); 808 LoadBackendIfNecessary(); 809 uint32* next_id = new uint32(content::DownloadItem::kInvalidId); 810 thread_->message_loop_proxy()->PostTaskAndReply( 811 FROM_HERE, 812 base::Bind(&HistoryBackend::GetNextDownloadId, 813 history_backend_.get(), 814 next_id), 815 base::Bind(&DerefPODType<uint32>, callback, base::Owned(next_id))); 816 } 817 818 // Handle queries for a list of all downloads in the history database's 819 // 'downloads' table. 820 void HistoryService::QueryDownloads( 821 const DownloadQueryCallback& callback) { 822 DCHECK(thread_) << "History service being called after cleanup"; 823 DCHECK(thread_checker_.CalledOnValidThread()); 824 LoadBackendIfNecessary(); 825 std::vector<history::DownloadRow>* rows = 826 new std::vector<history::DownloadRow>(); 827 scoped_ptr<std::vector<history::DownloadRow> > scoped_rows(rows); 828 // Beware! The first Bind() does not simply |scoped_rows.get()| because 829 // base::Passed(&scoped_rows) nullifies |scoped_rows|, and compilers do not 830 // guarantee that the first Bind's arguments are evaluated before the second 831 // Bind's arguments. 832 thread_->message_loop_proxy()->PostTaskAndReply( 833 FROM_HERE, 834 base::Bind(&HistoryBackend::QueryDownloads, history_backend_.get(), rows), 835 base::Bind(callback, base::Passed(&scoped_rows))); 836 } 837 838 // Handle updates for a particular download. This is a 'fire and forget' 839 // operation, so we don't need to be called back. 840 void HistoryService::UpdateDownload(const history::DownloadRow& data) { 841 DCHECK(thread_checker_.CalledOnValidThread()); 842 ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::UpdateDownload, data); 843 } 844 845 void HistoryService::RemoveDownloads(const std::set<uint32>& ids) { 846 DCHECK(thread_checker_.CalledOnValidThread()); 847 ScheduleAndForget(PRIORITY_NORMAL, 848 &HistoryBackend::RemoveDownloads, ids); 849 } 850 851 HistoryService::Handle HistoryService::QueryHistory( 852 const base::string16& text_query, 853 const history::QueryOptions& options, 854 CancelableRequestConsumerBase* consumer, 855 const QueryHistoryCallback& callback) { 856 DCHECK(thread_checker_.CalledOnValidThread()); 857 return Schedule(PRIORITY_UI, &HistoryBackend::QueryHistory, consumer, 858 new history::QueryHistoryRequest(callback), 859 text_query, options); 860 } 861 862 HistoryService::Handle HistoryService::QueryRedirectsFrom( 863 const GURL& from_url, 864 CancelableRequestConsumerBase* consumer, 865 const QueryRedirectsCallback& callback) { 866 DCHECK(thread_checker_.CalledOnValidThread()); 867 return Schedule(PRIORITY_UI, &HistoryBackend::QueryRedirectsFrom, consumer, 868 new history::QueryRedirectsRequest(callback), from_url); 869 } 870 871 HistoryService::Handle HistoryService::QueryRedirectsTo( 872 const GURL& to_url, 873 CancelableRequestConsumerBase* consumer, 874 const QueryRedirectsCallback& callback) { 875 DCHECK(thread_checker_.CalledOnValidThread()); 876 return Schedule(PRIORITY_NORMAL, &HistoryBackend::QueryRedirectsTo, consumer, 877 new history::QueryRedirectsRequest(callback), to_url); 878 } 879 880 HistoryService::Handle HistoryService::GetVisibleVisitCountToHost( 881 const GURL& url, 882 CancelableRequestConsumerBase* consumer, 883 const GetVisibleVisitCountToHostCallback& callback) { 884 DCHECK(thread_checker_.CalledOnValidThread()); 885 return Schedule(PRIORITY_UI, &HistoryBackend::GetVisibleVisitCountToHost, 886 consumer, new history::GetVisibleVisitCountToHostRequest(callback), url); 887 } 888 889 HistoryService::Handle HistoryService::QueryTopURLsAndRedirects( 890 int result_count, 891 CancelableRequestConsumerBase* consumer, 892 const QueryTopURLsAndRedirectsCallback& callback) { 893 DCHECK(thread_checker_.CalledOnValidThread()); 894 return Schedule(PRIORITY_NORMAL, &HistoryBackend::QueryTopURLsAndRedirects, 895 consumer, new history::QueryTopURLsAndRedirectsRequest(callback), 896 result_count); 897 } 898 899 HistoryService::Handle HistoryService::QueryMostVisitedURLs( 900 int result_count, 901 int days_back, 902 CancelableRequestConsumerBase* consumer, 903 const QueryMostVisitedURLsCallback& callback) { 904 DCHECK(thread_checker_.CalledOnValidThread()); 905 return Schedule(PRIORITY_NORMAL, &HistoryBackend::QueryMostVisitedURLs, 906 consumer, 907 new history::QueryMostVisitedURLsRequest(callback), 908 result_count, days_back); 909 } 910 911 HistoryService::Handle HistoryService::QueryFilteredURLs( 912 int result_count, 913 const history::VisitFilter& filter, 914 bool extended_info, 915 CancelableRequestConsumerBase* consumer, 916 const QueryFilteredURLsCallback& callback) { 917 DCHECK(thread_checker_.CalledOnValidThread()); 918 return Schedule(PRIORITY_NORMAL, 919 &HistoryBackend::QueryFilteredURLs, 920 consumer, 921 new history::QueryFilteredURLsRequest(callback), 922 result_count, filter, extended_info); 923 } 924 925 void HistoryService::Observe(int type, 926 const content::NotificationSource& source, 927 const content::NotificationDetails& details) { 928 DCHECK(thread_checker_.CalledOnValidThread()); 929 if (!thread_) 930 return; 931 932 switch (type) { 933 case chrome::NOTIFICATION_HISTORY_URLS_DELETED: { 934 // Update the visited link system for deleted URLs. We will update the 935 // visited link system for added URLs as soon as we get the add 936 // notification (we don't have to wait for the backend, which allows us to 937 // be faster to update the state). 938 // 939 // For deleted URLs, we don't typically know what will be deleted since 940 // delete notifications are by time. We would also like to be more 941 // respectful of privacy and never tell the user something is gone when it 942 // isn't. Therefore, we update the delete URLs after the fact. 943 if (visitedlink_master_) { 944 content::Details<history::URLsDeletedDetails> deleted_details(details); 945 946 if (deleted_details->all_history) { 947 visitedlink_master_->DeleteAllURLs(); 948 } else { 949 URLIteratorFromURLRows iterator(deleted_details->rows); 950 visitedlink_master_->DeleteURLs(&iterator); 951 } 952 } 953 break; 954 } 955 956 case chrome::NOTIFICATION_TEMPLATE_URL_REMOVED: 957 DeleteAllSearchTermsForKeyword( 958 *(content::Details<TemplateURLID>(details).ptr())); 959 break; 960 961 default: 962 NOTREACHED(); 963 } 964 } 965 966 void HistoryService::RebuildTable( 967 const scoped_refptr<URLEnumerator>& enumerator) { 968 DCHECK(thread_checker_.CalledOnValidThread()); 969 ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::IterateURLs, enumerator); 970 } 971 972 bool HistoryService::Init(const base::FilePath& history_dir, 973 BookmarkService* bookmark_service, 974 bool no_db) { 975 DCHECK(thread_checker_.CalledOnValidThread()); 976 if (!thread_->Start()) { 977 Cleanup(); 978 return false; 979 } 980 981 history_dir_ = history_dir; 982 bookmark_service_ = bookmark_service; 983 no_db_ = no_db; 984 985 if (profile_) { 986 std::string languages = 987 profile_->GetPrefs()->GetString(prefs::kAcceptLanguages); 988 in_memory_url_index_.reset( 989 new history::InMemoryURLIndex(profile_, history_dir_, languages)); 990 in_memory_url_index_->Init(); 991 } 992 993 // Create the history backend. 994 LoadBackendIfNecessary(); 995 996 if (visitedlink_master_) { 997 bool result = visitedlink_master_->Init(); 998 DCHECK(result); 999 } 1000 1001 return true; 1002 } 1003 1004 void HistoryService::ScheduleAutocomplete(HistoryURLProvider* provider, 1005 HistoryURLProviderParams* params) { 1006 DCHECK(thread_checker_.CalledOnValidThread()); 1007 ScheduleAndForget(PRIORITY_UI, &HistoryBackend::ScheduleAutocomplete, 1008 scoped_refptr<HistoryURLProvider>(provider), params); 1009 } 1010 1011 void HistoryService::ScheduleTask(SchedulePriority priority, 1012 const base::Closure& task) { 1013 DCHECK(thread_checker_.CalledOnValidThread()); 1014 CHECK(thread_); 1015 CHECK(thread_->message_loop()); 1016 // TODO(brettw): Do prioritization. 1017 thread_->message_loop()->PostTask(FROM_HERE, task); 1018 } 1019 1020 // static 1021 bool HistoryService::CanAddURL(const GURL& url) { 1022 if (!url.is_valid()) 1023 return false; 1024 1025 // TODO: We should allow kChromeUIScheme URLs if they have been explicitly 1026 // typed. Right now, however, these are marked as typed even when triggered 1027 // by a shortcut or menu action. 1028 if (url.SchemeIs(content::kJavaScriptScheme) || 1029 url.SchemeIs(chrome::kChromeDevToolsScheme) || 1030 url.SchemeIs(chrome::kChromeNativeScheme) || 1031 url.SchemeIs(chrome::kChromeUIScheme) || 1032 url.SchemeIs(chrome::kChromeSearchScheme) || 1033 url.SchemeIs(content::kViewSourceScheme)) 1034 return false; 1035 1036 // Allow all about: and chrome: URLs except about:blank, since the user may 1037 // like to see "chrome://memory/", etc. in their history and autocomplete. 1038 if (url == GURL(content::kAboutBlankURL)) 1039 return false; 1040 1041 return true; 1042 } 1043 1044 base::WeakPtr<HistoryService> HistoryService::AsWeakPtr() { 1045 DCHECK(thread_checker_.CalledOnValidThread()); 1046 return weak_ptr_factory_.GetWeakPtr(); 1047 } 1048 1049 syncer::SyncMergeResult HistoryService::MergeDataAndStartSyncing( 1050 syncer::ModelType type, 1051 const syncer::SyncDataList& initial_sync_data, 1052 scoped_ptr<syncer::SyncChangeProcessor> sync_processor, 1053 scoped_ptr<syncer::SyncErrorFactory> error_handler) { 1054 DCHECK(thread_checker_.CalledOnValidThread()); 1055 DCHECK_EQ(type, syncer::HISTORY_DELETE_DIRECTIVES); 1056 delete_directive_handler_.Start(this, initial_sync_data, 1057 sync_processor.Pass()); 1058 return syncer::SyncMergeResult(type); 1059 } 1060 1061 void HistoryService::StopSyncing(syncer::ModelType type) { 1062 DCHECK(thread_checker_.CalledOnValidThread()); 1063 DCHECK_EQ(type, syncer::HISTORY_DELETE_DIRECTIVES); 1064 delete_directive_handler_.Stop(); 1065 } 1066 1067 syncer::SyncDataList HistoryService::GetAllSyncData( 1068 syncer::ModelType type) const { 1069 DCHECK(thread_checker_.CalledOnValidThread()); 1070 DCHECK_EQ(type, syncer::HISTORY_DELETE_DIRECTIVES); 1071 // TODO(akalin): Keep track of existing delete directives. 1072 return syncer::SyncDataList(); 1073 } 1074 1075 syncer::SyncError HistoryService::ProcessSyncChanges( 1076 const tracked_objects::Location& from_here, 1077 const syncer::SyncChangeList& change_list) { 1078 delete_directive_handler_.ProcessSyncChanges(this, change_list); 1079 return syncer::SyncError(); 1080 } 1081 1082 syncer::SyncError HistoryService::ProcessLocalDeleteDirective( 1083 const sync_pb::HistoryDeleteDirectiveSpecifics& delete_directive) { 1084 DCHECK(thread_checker_.CalledOnValidThread()); 1085 return delete_directive_handler_.ProcessLocalDeleteDirective( 1086 delete_directive); 1087 } 1088 1089 void HistoryService::SetInMemoryBackend( 1090 int backend_id, scoped_ptr<history::InMemoryHistoryBackend> mem_backend) { 1091 DCHECK(thread_checker_.CalledOnValidThread()); 1092 if (!history_backend_.get() || current_backend_id_ != backend_id) { 1093 DVLOG(1) << "Message from obsolete backend"; 1094 // mem_backend is deleted. 1095 return; 1096 } 1097 DCHECK(!in_memory_backend_) << "Setting mem DB twice"; 1098 in_memory_backend_.reset(mem_backend.release()); 1099 1100 // The database requires additional initialization once we own it. 1101 in_memory_backend_->AttachToHistoryService(profile_); 1102 } 1103 1104 void HistoryService::NotifyProfileError(int backend_id, 1105 sql::InitStatus init_status) { 1106 DCHECK(thread_checker_.CalledOnValidThread()); 1107 if (!history_backend_.get() || current_backend_id_ != backend_id) { 1108 DVLOG(1) << "Message from obsolete backend"; 1109 return; 1110 } 1111 ShowProfileErrorDialog( 1112 PROFILE_ERROR_HISTORY, 1113 (init_status == sql::INIT_FAILURE) ? 1114 IDS_COULDNT_OPEN_PROFILE_ERROR : IDS_PROFILE_TOO_NEW_ERROR); 1115 } 1116 1117 void HistoryService::DeleteURL(const GURL& url) { 1118 DCHECK(thread_checker_.CalledOnValidThread()); 1119 // We will update the visited links when we observe the delete notifications. 1120 ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::DeleteURL, url); 1121 } 1122 1123 void HistoryService::DeleteURLsForTest(const std::vector<GURL>& urls) { 1124 DCHECK(thread_checker_.CalledOnValidThread()); 1125 // We will update the visited links when we observe the delete 1126 // notifications. 1127 ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::DeleteURLs, urls); 1128 } 1129 1130 void HistoryService::ExpireHistoryBetween( 1131 const std::set<GURL>& restrict_urls, 1132 Time begin_time, 1133 Time end_time, 1134 const base::Closure& callback, 1135 CancelableTaskTracker* tracker) { 1136 DCHECK(thread_); 1137 DCHECK(thread_checker_.CalledOnValidThread()); 1138 DCHECK(history_backend_.get()); 1139 tracker->PostTaskAndReply(thread_->message_loop_proxy().get(), 1140 FROM_HERE, 1141 base::Bind(&HistoryBackend::ExpireHistoryBetween, 1142 history_backend_, 1143 restrict_urls, 1144 begin_time, 1145 end_time), 1146 callback); 1147 } 1148 1149 void HistoryService::ExpireHistory( 1150 const std::vector<history::ExpireHistoryArgs>& expire_list, 1151 const base::Closure& callback, 1152 CancelableTaskTracker* tracker) { 1153 DCHECK(thread_); 1154 DCHECK(thread_checker_.CalledOnValidThread()); 1155 DCHECK(history_backend_.get()); 1156 tracker->PostTaskAndReply( 1157 thread_->message_loop_proxy().get(), 1158 FROM_HERE, 1159 base::Bind(&HistoryBackend::ExpireHistory, history_backend_, expire_list), 1160 callback); 1161 } 1162 1163 void HistoryService::ExpireLocalAndRemoteHistoryBetween( 1164 const std::set<GURL>& restrict_urls, 1165 Time begin_time, 1166 Time end_time, 1167 const base::Closure& callback, 1168 CancelableTaskTracker* tracker) { 1169 // TODO(dubroy): This should be factored out into a separate class that 1170 // dispatches deletions to the proper places. 1171 1172 history::WebHistoryService* web_history = 1173 WebHistoryServiceFactory::GetForProfile(profile_); 1174 if (web_history) { 1175 // TODO(dubroy): This API does not yet support deletion of specific URLs. 1176 DCHECK(restrict_urls.empty()); 1177 1178 delete_directive_handler_.CreateDeleteDirectives( 1179 std::set<int64>(), begin_time, end_time); 1180 1181 // Attempt online deletion from the history server, but ignore the result. 1182 // Deletion directives ensure that the results will eventually be deleted. 1183 // Pass ownership of the request to the callback. 1184 scoped_ptr<history::WebHistoryService::Request> request = 1185 web_history->ExpireHistoryBetween( 1186 restrict_urls, begin_time, end_time, 1187 base::Bind(&ExpireWebHistoryComplete)); 1188 1189 // The request will be freed when the callback is called. 1190 CHECK(request.release()); 1191 } 1192 ExpireHistoryBetween(restrict_urls, begin_time, end_time, callback, tracker); 1193 } 1194 1195 void HistoryService::BroadcastNotificationsHelper( 1196 int type, 1197 history::HistoryDetails* details) { 1198 DCHECK(thread_checker_.CalledOnValidThread()); 1199 // TODO(evanm): this is currently necessitated by generate_profile, which 1200 // runs without a browser process. generate_profile should really create 1201 // a browser process, at which point this check can then be nuked. 1202 if (!g_browser_process) 1203 return; 1204 1205 if (!thread_) 1206 return; 1207 1208 // The source of all of our notifications is the profile. Note that this 1209 // pointer is NULL in unit tests. 1210 content::Source<Profile> source(profile_); 1211 1212 // The details object just contains the pointer to the object that the 1213 // backend has allocated for us. The receiver of the notification will cast 1214 // this to the proper type. 1215 content::Details<history::HistoryDetails> det(details); 1216 1217 content::NotificationService::current()->Notify(type, source, det); 1218 } 1219 1220 void HistoryService::LoadBackendIfNecessary() { 1221 DCHECK(thread_checker_.CalledOnValidThread()); 1222 if (!thread_ || history_backend_.get()) 1223 return; // Failed to init, or already started loading. 1224 1225 ++current_backend_id_; 1226 scoped_refptr<HistoryBackend> backend( 1227 new HistoryBackend(history_dir_, 1228 current_backend_id_, 1229 new BackendDelegate( 1230 weak_ptr_factory_.GetWeakPtr(), 1231 base::ThreadTaskRunnerHandle::Get(), 1232 profile_), 1233 bookmark_service_)); 1234 history_backend_.swap(backend); 1235 1236 // There may not be a profile when unit testing. 1237 std::string languages; 1238 if (profile_) { 1239 PrefService* prefs = profile_->GetPrefs(); 1240 languages = prefs->GetString(prefs::kAcceptLanguages); 1241 } 1242 ScheduleAndForget(PRIORITY_UI, &HistoryBackend::Init, languages, no_db_); 1243 } 1244 1245 void HistoryService::OnDBLoaded(int backend_id) { 1246 DCHECK(thread_checker_.CalledOnValidThread()); 1247 if (!history_backend_.get() || current_backend_id_ != backend_id) { 1248 DVLOG(1) << "Message from obsolete backend"; 1249 return; 1250 } 1251 backend_loaded_ = true; 1252 content::NotificationService::current()->Notify( 1253 chrome::NOTIFICATION_HISTORY_LOADED, 1254 content::Source<Profile>(profile_), 1255 content::Details<HistoryService>(this)); 1256 } 1257 1258 bool HistoryService::GetRowForURL(const GURL& url, history::URLRow* url_row) { 1259 DCHECK(thread_checker_.CalledOnValidThread()); 1260 history::URLDatabase* db = InMemoryDatabase(); 1261 return db && (db->GetRowForURL(url, url_row) != 0); 1262 } 1263 1264 void HistoryService::AddVisitDatabaseObserver( 1265 history::VisitDatabaseObserver* observer) { 1266 DCHECK(thread_checker_.CalledOnValidThread()); 1267 visit_database_observers_.AddObserver(observer); 1268 } 1269 1270 void HistoryService::RemoveVisitDatabaseObserver( 1271 history::VisitDatabaseObserver* observer) { 1272 DCHECK(thread_checker_.CalledOnValidThread()); 1273 visit_database_observers_.RemoveObserver(observer); 1274 } 1275 1276 void HistoryService::NotifyVisitDBObserversOnAddVisit( 1277 const history::BriefVisitInfo& info) { 1278 DCHECK(thread_checker_.CalledOnValidThread()); 1279 FOR_EACH_OBSERVER(history::VisitDatabaseObserver, visit_database_observers_, 1280 OnAddVisit(info)); 1281 } 1282