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