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