• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 // The history system runs on a background thread so that potentially slow
6 // database operations don't delay the browser. This backend processing is
7 // represented by HistoryBackend. The HistoryService's job is to dispatch to
8 // that thread.
9 //
10 // Main thread                       History thread
11 // -----------                       --------------
12 // HistoryService <----------------> HistoryBackend
13 //                                   -> HistoryDatabase
14 //                                      -> SQLite connection to History
15 //                                   -> ArchivedDatabase
16 //                                      -> SQLite connection to Archived History
17 //                                   -> TextDatabaseManager
18 //                                      -> SQLite connection to one month's data
19 //                                      -> SQLite connection to one month's data
20 //                                      ...
21 //                                   -> ThumbnailDatabase
22 //                                      -> SQLite connection to Thumbnails
23 //                                         (and favicons)
24 
25 #include "chrome/browser/history/history.h"
26 
27 #include "base/callback.h"
28 #include "base/memory/ref_counted.h"
29 #include "base/message_loop.h"
30 #include "base/path_service.h"
31 #include "base/string_util.h"
32 #include "base/task.h"
33 #include "chrome/browser/autocomplete/history_url_provider.h"
34 #include "chrome/browser/browser_process.h"
35 #include "chrome/browser/history/download_create_info.h"
36 #include "chrome/browser/history/history_backend.h"
37 #include "chrome/browser/history/history_notifications.h"
38 #include "chrome/browser/history/history_types.h"
39 #include "chrome/browser/history/in_memory_database.h"
40 #include "chrome/browser/history/in_memory_history_backend.h"
41 #include "chrome/browser/history/top_sites.h"
42 #include "chrome/browser/prefs/pref_service.h"
43 #include "chrome/browser/profiles/profile.h"
44 #include "chrome/browser/ui/profile_error_dialog.h"
45 #include "chrome/browser/visitedlink/visitedlink_master.h"
46 #include "chrome/common/chrome_constants.h"
47 #include "chrome/common/pref_names.h"
48 #include "chrome/common/thumbnail_score.h"
49 #include "chrome/common/url_constants.h"
50 #include "content/browser/browser_thread.h"
51 #include "content/common/notification_service.h"
52 #include "grit/chromium_strings.h"
53 #include "grit/generated_resources.h"
54 #include "third_party/skia/include/core/SkBitmap.h"
55 
56 using base::Time;
57 using history::HistoryBackend;
58 
59 namespace {
60 
61 static const char* kHistoryThreadName = "Chrome_HistoryThread";
62 
63 }  // namespace
64 
65 // Sends messages from the backend to us on the main thread. This must be a
66 // separate class from the history service so that it can hold a reference to
67 // the history service (otherwise we would have to manually AddRef and
68 // Release when the Backend has a reference to us).
69 class HistoryService::BackendDelegate : public HistoryBackend::Delegate {
70  public:
BackendDelegate(HistoryService * history_service)71   explicit BackendDelegate(HistoryService* history_service)
72       : history_service_(history_service),
73         message_loop_(MessageLoop::current()) {
74   }
75 
NotifyProfileError(sql::InitStatus init_status)76   virtual void NotifyProfileError(sql::InitStatus init_status) OVERRIDE {
77     // Send to the history service on the main thread.
78     message_loop_->PostTask(FROM_HERE, NewRunnableMethod(history_service_.get(),
79         &HistoryService::NotifyProfileError, init_status));
80   }
81 
SetInMemoryBackend(history::InMemoryHistoryBackend * backend)82   virtual void SetInMemoryBackend(
83       history::InMemoryHistoryBackend* backend) OVERRIDE {
84     // Send the backend to the history service on the main thread.
85     message_loop_->PostTask(FROM_HERE, NewRunnableMethod(history_service_.get(),
86         &HistoryService::SetInMemoryBackend, backend));
87   }
88 
BroadcastNotifications(NotificationType type,history::HistoryDetails * details)89   virtual void BroadcastNotifications(
90       NotificationType type,
91       history::HistoryDetails* details) OVERRIDE {
92     // Send the notification on the history thread.
93     if (NotificationService::current()) {
94       Details<history::HistoryDetails> det(details);
95       NotificationService::current()->Notify(type,
96                                              NotificationService::AllSources(),
97                                              det);
98     }
99     // Send the notification to the history service on the main thread.
100     message_loop_->PostTask(FROM_HERE, NewRunnableMethod(history_service_.get(),
101         &HistoryService::BroadcastNotifications, type, details));
102   }
103 
DBLoaded()104   virtual void DBLoaded() OVERRIDE {
105     message_loop_->PostTask(FROM_HERE, NewRunnableMethod(history_service_.get(),
106         &HistoryService::OnDBLoaded));
107   }
108 
StartTopSitesMigration()109   virtual void StartTopSitesMigration() OVERRIDE {
110     message_loop_->PostTask(FROM_HERE, NewRunnableMethod(history_service_.get(),
111         &HistoryService::StartTopSitesMigration));
112   }
113 
114  private:
115   scoped_refptr<HistoryService> history_service_;
116   MessageLoop* message_loop_;
117 };
118 
119 // static
120 const history::StarID HistoryService::kBookmarkBarID = 1;
121 
122 // The history thread is intentionally not a BrowserThread because the
123 // sync integration unit tests depend on being able to create more than one
124 // history thread.
HistoryService()125 HistoryService::HistoryService()
126     : thread_(new base::Thread(kHistoryThreadName)),
127       profile_(NULL),
128       backend_loaded_(false),
129       bookmark_service_(NULL),
130       no_db_(false),
131       needs_top_sites_migration_(false) {
132 }
133 
HistoryService(Profile * profile)134 HistoryService::HistoryService(Profile* profile)
135     : thread_(new base::Thread(kHistoryThreadName)),
136       profile_(profile),
137       backend_loaded_(false),
138       bookmark_service_(NULL),
139       no_db_(false),
140       needs_top_sites_migration_(false) {
141   DCHECK(profile_);
142   registrar_.Add(this, NotificationType::HISTORY_URLS_DELETED,
143                  Source<Profile>(profile_));
144   registrar_.Add(this, NotificationType::TEMPLATE_URL_REMOVED,
145                  Source<Profile>(profile_));
146 }
147 
~HistoryService()148 HistoryService::~HistoryService() {
149   // Shutdown the backend. This does nothing if Cleanup was already invoked.
150   Cleanup();
151 }
152 
BackendLoaded()153 bool HistoryService::BackendLoaded() {
154   // NOTE: We start the backend loading even though it completes asynchronously
155   // and thus won't affect the return value of this function.  This is because
156   // callers of this assume that if the backend isn't yet loaded it will be
157   // soon, so they will either listen for notifications or just retry this call
158   // later.  If we've purged the backend, we haven't necessarily restarted it
159   // loading by now, so we need to trigger the load in order to maintain that
160   // expectation.
161   LoadBackendIfNecessary();
162   return backend_loaded_;
163 }
164 
UnloadBackend()165 void HistoryService::UnloadBackend() {
166   if (!history_backend_)
167     return;  // Already unloaded.
168 
169   // Get rid of the in-memory backend.
170   in_memory_backend_.reset();
171 
172   // The backend's destructor must run on the history thread since it is not
173   // threadsafe. So this thread must not be the last thread holding a reference
174   // to the backend, or a crash could happen.
175   //
176   // We have a reference to the history backend. There is also an extra
177   // reference held by our delegate installed in the backend, which
178   // HistoryBackend::Closing will release. This means if we scheduled a call
179   // to HistoryBackend::Closing and *then* released our backend reference, there
180   // will be a race between us and the backend's Closing function to see who is
181   // the last holder of a reference. If the backend thread's Closing manages to
182   // run before we release our backend refptr, the last reference will be held
183   // by this thread and the destructor will be called from here.
184   //
185   // Therefore, we create a task to run the Closing operation first. This holds
186   // a reference to the backend. Then we release our reference, then we schedule
187   // the task to run. After the task runs, it will delete its reference from
188   // the history thread, ensuring everything works properly.
189   Task* closing_task =
190       NewRunnableMethod(history_backend_.get(), &HistoryBackend::Closing);
191   history_backend_ = NULL;
192   ScheduleTask(PRIORITY_NORMAL, closing_task);
193 }
194 
Cleanup()195 void HistoryService::Cleanup() {
196   if (!thread_) {
197     // We've already cleaned up.
198     return;
199   }
200 
201   // Unload the backend.
202   UnloadBackend();
203 
204   // Delete the thread, which joins with the background thread. We defensively
205   // NULL the pointer before deleting it in case somebody tries to use it
206   // during shutdown, but this shouldn't happen.
207   base::Thread* thread = thread_;
208   thread_ = NULL;
209   delete thread;
210 }
211 
NotifyRenderProcessHostDestruction(const void * host)212 void HistoryService::NotifyRenderProcessHostDestruction(const void* host) {
213   ScheduleAndForget(PRIORITY_NORMAL,
214                     &HistoryBackend::NotifyRenderProcessHostDestruction, host);
215 }
216 
InMemoryDatabase()217 history::URLDatabase* HistoryService::InMemoryDatabase() {
218   // NOTE: See comments in BackendLoaded() as to why we call
219   // LoadBackendIfNecessary() here even though it won't affect the return value
220   // for this call.
221   LoadBackendIfNecessary();
222   if (in_memory_backend_.get())
223     return in_memory_backend_->db();
224   return NULL;
225 }
226 
InMemoryIndex()227 history::InMemoryURLIndex* HistoryService::InMemoryIndex() {
228   // NOTE: See comments in BackendLoaded() as to why we call
229   // LoadBackendIfNecessary() here even though it won't affect the return value
230   // for this call.
231   LoadBackendIfNecessary();
232   if (in_memory_backend_.get())
233     return in_memory_backend_->InMemoryIndex();
234   return NULL;
235 }
236 
SetSegmentPresentationIndex(int64 segment_id,int index)237 void HistoryService::SetSegmentPresentationIndex(int64 segment_id, int index) {
238   ScheduleAndForget(PRIORITY_UI,
239                     &HistoryBackend::SetSegmentPresentationIndex,
240                     segment_id, index);
241 }
242 
SetKeywordSearchTermsForURL(const GURL & url,TemplateURLID keyword_id,const string16 & term)243 void HistoryService::SetKeywordSearchTermsForURL(const GURL& url,
244                                                  TemplateURLID keyword_id,
245                                                  const string16& term) {
246   ScheduleAndForget(PRIORITY_UI,
247                     &HistoryBackend::SetKeywordSearchTermsForURL,
248                     url, keyword_id, term);
249 }
250 
DeleteAllSearchTermsForKeyword(TemplateURLID keyword_id)251 void HistoryService::DeleteAllSearchTermsForKeyword(
252     TemplateURLID keyword_id) {
253   ScheduleAndForget(PRIORITY_UI,
254                     &HistoryBackend::DeleteAllSearchTermsForKeyword,
255                     keyword_id);
256 }
257 
GetMostRecentKeywordSearchTerms(TemplateURLID keyword_id,const string16 & prefix,int max_count,CancelableRequestConsumerBase * consumer,GetMostRecentKeywordSearchTermsCallback * callback)258 HistoryService::Handle HistoryService::GetMostRecentKeywordSearchTerms(
259     TemplateURLID keyword_id,
260     const string16& prefix,
261     int max_count,
262     CancelableRequestConsumerBase* consumer,
263     GetMostRecentKeywordSearchTermsCallback* callback) {
264   return Schedule(PRIORITY_UI, &HistoryBackend::GetMostRecentKeywordSearchTerms,
265                   consumer,
266                   new history::GetMostRecentKeywordSearchTermsRequest(callback),
267                   keyword_id, prefix, max_count);
268 }
269 
URLsNoLongerBookmarked(const std::set<GURL> & urls)270 void HistoryService::URLsNoLongerBookmarked(const std::set<GURL>& urls) {
271   ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::URLsNoLongerBookmarked,
272                     urls);
273 }
274 
ScheduleDBTask(HistoryDBTask * task,CancelableRequestConsumerBase * consumer)275 HistoryService::Handle HistoryService::ScheduleDBTask(
276     HistoryDBTask* task,
277     CancelableRequestConsumerBase* consumer) {
278   history::HistoryDBTaskRequest* request = new history::HistoryDBTaskRequest(
279       NewCallback(task, &HistoryDBTask::DoneRunOnMainThread));
280   request->value = task;  // The value is the task to execute.
281   return Schedule(PRIORITY_UI, &HistoryBackend::ProcessDBTask, consumer,
282                   request);
283 }
284 
QuerySegmentUsageSince(CancelableRequestConsumerBase * consumer,const Time from_time,int max_result_count,SegmentQueryCallback * callback)285 HistoryService::Handle HistoryService::QuerySegmentUsageSince(
286     CancelableRequestConsumerBase* consumer,
287     const Time from_time,
288     int max_result_count,
289     SegmentQueryCallback* callback) {
290   return Schedule(PRIORITY_UI, &HistoryBackend::QuerySegmentUsage,
291                   consumer, new history::QuerySegmentUsageRequest(callback),
292                   from_time, max_result_count);
293 }
294 
SetOnBackendDestroyTask(Task * task)295 void HistoryService::SetOnBackendDestroyTask(Task* task) {
296   ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::SetOnBackendDestroyTask,
297                     MessageLoop::current(), task);
298 }
299 
AddPage(const GURL & url,const void * id_scope,int32 page_id,const GURL & referrer,PageTransition::Type transition,const history::RedirectList & redirects,history::VisitSource visit_source,bool did_replace_entry)300 void HistoryService::AddPage(const GURL& url,
301                              const void* id_scope,
302                              int32 page_id,
303                              const GURL& referrer,
304                              PageTransition::Type transition,
305                              const history::RedirectList& redirects,
306                              history::VisitSource visit_source,
307                              bool did_replace_entry) {
308   AddPage(url, Time::Now(), id_scope, page_id, referrer, transition, redirects,
309           visit_source, did_replace_entry);
310 }
311 
AddPage(const GURL & url,Time time,const void * id_scope,int32 page_id,const GURL & referrer,PageTransition::Type transition,const history::RedirectList & redirects,history::VisitSource visit_source,bool did_replace_entry)312 void HistoryService::AddPage(const GURL& url,
313                              Time time,
314                              const void* id_scope,
315                              int32 page_id,
316                              const GURL& referrer,
317                              PageTransition::Type transition,
318                              const history::RedirectList& redirects,
319                              history::VisitSource visit_source,
320                              bool did_replace_entry) {
321   scoped_refptr<history::HistoryAddPageArgs> request(
322       new history::HistoryAddPageArgs(url, time, id_scope, page_id, referrer,
323                                       redirects, transition, visit_source,
324                                       did_replace_entry));
325   AddPage(*request);
326 }
327 
AddPage(const history::HistoryAddPageArgs & add_page_args)328 void HistoryService::AddPage(const history::HistoryAddPageArgs& add_page_args) {
329   DCHECK(thread_) << "History service being called after cleanup";
330 
331   // Filter out unwanted URLs. We don't add auto-subframe URLs. They are a
332   // large part of history (think iframes for ads) and we never display them in
333   // history UI. We will still add manual subframes, which are ones the user
334   // has clicked on to get.
335   if (!CanAddURL(add_page_args.url))
336     return;
337 
338   // Add link & all redirects to visited link list.
339   VisitedLinkMaster* visited_links;
340   if (profile_ && (visited_links = profile_->GetVisitedLinkMaster())) {
341     visited_links->AddURL(add_page_args.url);
342 
343     if (!add_page_args.redirects.empty()) {
344       // We should not be asked to add a page in the middle of a redirect chain.
345       DCHECK_EQ(add_page_args.url,
346                 add_page_args.redirects[add_page_args.redirects.size() - 1]);
347 
348       // We need the !redirects.empty() condition above since size_t is unsigned
349       // and will wrap around when we subtract one from a 0 size.
350       for (size_t i = 0; i < add_page_args.redirects.size() - 1; i++)
351         visited_links->AddURL(add_page_args.redirects[i]);
352     }
353   }
354 
355   ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::AddPage,
356                     scoped_refptr<history::HistoryAddPageArgs>(
357                         add_page_args.Clone()));
358 }
359 
AddPageNoVisitForBookmark(const GURL & url)360 void HistoryService::AddPageNoVisitForBookmark(const GURL& url) {
361   if (!CanAddURL(url))
362     return;
363 
364   ScheduleAndForget(PRIORITY_NORMAL,
365                     &HistoryBackend::AddPageNoVisitForBookmark, url);
366 }
367 
SetPageTitle(const GURL & url,const string16 & title)368 void HistoryService::SetPageTitle(const GURL& url,
369                                   const string16& title) {
370   ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::SetPageTitle, url, title);
371 }
372 
AddPageWithDetails(const GURL & url,const string16 & title,int visit_count,int typed_count,Time last_visit,bool hidden,history::VisitSource visit_source)373 void HistoryService::AddPageWithDetails(const GURL& url,
374                                         const string16& title,
375                                         int visit_count,
376                                         int typed_count,
377                                         Time last_visit,
378                                         bool hidden,
379                                         history::VisitSource visit_source) {
380   // Filter out unwanted URLs.
381   if (!CanAddURL(url))
382     return;
383 
384   // Add to the visited links system.
385   VisitedLinkMaster* visited_links;
386   if (profile_ && (visited_links = profile_->GetVisitedLinkMaster()))
387     visited_links->AddURL(url);
388 
389   history::URLRow row(url);
390   row.set_title(title);
391   row.set_visit_count(visit_count);
392   row.set_typed_count(typed_count);
393   row.set_last_visit(last_visit);
394   row.set_hidden(hidden);
395 
396   std::vector<history::URLRow> rows;
397   rows.push_back(row);
398 
399   ScheduleAndForget(PRIORITY_NORMAL,
400                     &HistoryBackend::AddPagesWithDetails, rows, visit_source);
401 }
402 
AddPagesWithDetails(const std::vector<history::URLRow> & info,history::VisitSource visit_source)403 void HistoryService::AddPagesWithDetails(
404     const std::vector<history::URLRow>& info,
405     history::VisitSource visit_source) {
406 
407   // Add to the visited links system.
408   VisitedLinkMaster* visited_links;
409   if (profile_ && (visited_links = profile_->GetVisitedLinkMaster())) {
410     std::vector<GURL> urls;
411     urls.reserve(info.size());
412     for (std::vector<history::URLRow>::const_iterator i = info.begin();
413          i != info.end();
414          ++i)
415       urls.push_back(i->url());
416 
417     visited_links->AddURLs(urls);
418   }
419 
420   ScheduleAndForget(PRIORITY_NORMAL,
421                     &HistoryBackend::AddPagesWithDetails, info, visit_source);
422 }
423 
SetPageContents(const GURL & url,const string16 & contents)424 void HistoryService::SetPageContents(const GURL& url,
425                                      const string16& contents) {
426   if (!CanAddURL(url))
427     return;
428 
429   ScheduleAndForget(PRIORITY_LOW, &HistoryBackend::SetPageContents,
430                     url, contents);
431 }
432 
SetPageThumbnail(const GURL & page_url,const SkBitmap & thumbnail,const ThumbnailScore & score)433 void HistoryService::SetPageThumbnail(const GURL& page_url,
434                                       const SkBitmap& thumbnail,
435                                       const ThumbnailScore& score) {
436   if (!CanAddURL(page_url))
437     return;
438 
439   ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::SetPageThumbnail,
440                     page_url, thumbnail, score);
441 }
442 
GetPageThumbnail(const GURL & page_url,CancelableRequestConsumerBase * consumer,ThumbnailDataCallback * callback)443 HistoryService::Handle HistoryService::GetPageThumbnail(
444     const GURL& page_url,
445     CancelableRequestConsumerBase* consumer,
446     ThumbnailDataCallback* callback) {
447   return Schedule(PRIORITY_NORMAL, &HistoryBackend::GetPageThumbnail, consumer,
448                   new history::GetPageThumbnailRequest(callback), page_url);
449 }
450 
GetFavicon(FaviconService::GetFaviconRequest * request,const GURL & icon_url,history::IconType icon_type)451 void HistoryService::GetFavicon(FaviconService::GetFaviconRequest* request,
452                                 const GURL& icon_url,
453                                 history::IconType icon_type) {
454   Schedule(PRIORITY_NORMAL, &HistoryBackend::GetFavicon, NULL, request,
455            icon_url, icon_type);
456 }
457 
UpdateFaviconMappingAndFetch(FaviconService::GetFaviconRequest * request,const GURL & page_url,const GURL & icon_url,history::IconType icon_type)458 void HistoryService::UpdateFaviconMappingAndFetch(
459     FaviconService::GetFaviconRequest* request,
460     const GURL& page_url,
461     const GURL& icon_url,
462     history::IconType icon_type) {
463   Schedule(PRIORITY_NORMAL, &HistoryBackend::UpdateFaviconMappingAndFetch, NULL,
464            request, page_url, icon_url, history::FAVICON);
465 }
466 
GetFaviconForURL(FaviconService::GetFaviconRequest * request,const GURL & page_url,int icon_types)467 void HistoryService::GetFaviconForURL(
468     FaviconService::GetFaviconRequest* request,
469     const GURL& page_url,
470     int icon_types) {
471   Schedule(PRIORITY_NORMAL, &HistoryBackend::GetFaviconForURL, NULL, request,
472            page_url, icon_types);
473 }
474 
SetFavicon(const GURL & page_url,const GURL & icon_url,const std::vector<unsigned char> & image_data,history::IconType icon_type)475 void HistoryService::SetFavicon(const GURL& page_url,
476                                 const GURL& icon_url,
477                                 const std::vector<unsigned char>& image_data,
478                                 history::IconType icon_type) {
479   if (!CanAddURL(page_url))
480     return;
481 
482   ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::SetFavicon,
483       page_url, icon_url,
484       scoped_refptr<RefCountedMemory>(new RefCountedBytes(image_data)),
485       icon_type);
486 }
487 
SetFaviconOutOfDateForPage(const GURL & page_url)488 void HistoryService::SetFaviconOutOfDateForPage(const GURL& page_url) {
489   ScheduleAndForget(PRIORITY_NORMAL,
490                     &HistoryBackend::SetFaviconOutOfDateForPage, page_url);
491 }
492 
SetImportedFavicons(const std::vector<history::ImportedFaviconUsage> & favicon_usage)493 void HistoryService::SetImportedFavicons(
494     const std::vector<history::ImportedFaviconUsage>& favicon_usage) {
495   ScheduleAndForget(PRIORITY_NORMAL,
496                     &HistoryBackend::SetImportedFavicons, favicon_usage);
497 }
498 
IterateURLs(URLEnumerator * enumerator)499 void HistoryService::IterateURLs(URLEnumerator* enumerator) {
500   ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::IterateURLs, enumerator);
501 }
502 
QueryURL(const GURL & url,bool want_visits,CancelableRequestConsumerBase * consumer,QueryURLCallback * callback)503 HistoryService::Handle HistoryService::QueryURL(
504     const GURL& url,
505     bool want_visits,
506     CancelableRequestConsumerBase* consumer,
507     QueryURLCallback* callback) {
508   return Schedule(PRIORITY_UI, &HistoryBackend::QueryURL, consumer,
509                   new history::QueryURLRequest(callback), url, want_visits);
510 }
511 
512 // Downloads -------------------------------------------------------------------
513 
514 // Handle creation of a download by creating an entry in the history service's
515 // 'downloads' table.
CreateDownload(const DownloadCreateInfo & create_info,CancelableRequestConsumerBase * consumer,HistoryService::DownloadCreateCallback * callback)516 HistoryService::Handle HistoryService::CreateDownload(
517     const DownloadCreateInfo& create_info,
518     CancelableRequestConsumerBase* consumer,
519     HistoryService::DownloadCreateCallback* callback) {
520   return Schedule(PRIORITY_NORMAL, &HistoryBackend::CreateDownload, consumer,
521                   new history::DownloadCreateRequest(callback), create_info);
522 }
523 
524 // Handle queries for a list of all downloads in the history database's
525 // 'downloads' table.
QueryDownloads(CancelableRequestConsumerBase * consumer,DownloadQueryCallback * callback)526 HistoryService::Handle HistoryService::QueryDownloads(
527     CancelableRequestConsumerBase* consumer,
528     DownloadQueryCallback* callback) {
529   return Schedule(PRIORITY_NORMAL, &HistoryBackend::QueryDownloads, consumer,
530                   new history::DownloadQueryRequest(callback));
531 }
532 
533 // Changes all IN_PROGRESS in the database entries to CANCELED.
534 // IN_PROGRESS entries are the corrupted entries, not updated by next function
535 // because of the crash or some other extremal exit.
CleanUpInProgressEntries()536 void HistoryService::CleanUpInProgressEntries() {
537   ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::CleanUpInProgressEntries);
538 }
539 
540 // Handle updates for a particular download. This is a 'fire and forget'
541 // operation, so we don't need to be called back.
UpdateDownload(int64 received_bytes,int32 state,int64 db_handle)542 void HistoryService::UpdateDownload(int64 received_bytes,
543                                     int32 state,
544                                     int64 db_handle) {
545   ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::UpdateDownload,
546                     received_bytes, state, db_handle);
547 }
548 
UpdateDownloadPath(const FilePath & path,int64 db_handle)549 void HistoryService::UpdateDownloadPath(const FilePath& path,
550                                         int64 db_handle) {
551   ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::UpdateDownloadPath,
552                     path, db_handle);
553 }
554 
RemoveDownload(int64 db_handle)555 void HistoryService::RemoveDownload(int64 db_handle) {
556   ScheduleAndForget(PRIORITY_NORMAL,
557                     &HistoryBackend::RemoveDownload, db_handle);
558 }
559 
RemoveDownloadsBetween(Time remove_begin,Time remove_end)560 void HistoryService::RemoveDownloadsBetween(Time remove_begin,
561                                             Time remove_end) {
562   ScheduleAndForget(PRIORITY_NORMAL,
563                     &HistoryBackend::RemoveDownloadsBetween,
564                     remove_begin,
565                     remove_end);
566 }
567 
QueryHistory(const string16 & text_query,const history::QueryOptions & options,CancelableRequestConsumerBase * consumer,QueryHistoryCallback * callback)568 HistoryService::Handle HistoryService::QueryHistory(
569     const string16& text_query,
570     const history::QueryOptions& options,
571     CancelableRequestConsumerBase* consumer,
572     QueryHistoryCallback* callback) {
573   return Schedule(PRIORITY_UI, &HistoryBackend::QueryHistory, consumer,
574                   new history::QueryHistoryRequest(callback),
575                   text_query, options);
576 }
577 
QueryRedirectsFrom(const GURL & from_url,CancelableRequestConsumerBase * consumer,QueryRedirectsCallback * callback)578 HistoryService::Handle HistoryService::QueryRedirectsFrom(
579     const GURL& from_url,
580     CancelableRequestConsumerBase* consumer,
581     QueryRedirectsCallback* callback) {
582   return Schedule(PRIORITY_UI, &HistoryBackend::QueryRedirectsFrom, consumer,
583       new history::QueryRedirectsRequest(callback), from_url);
584 }
585 
QueryRedirectsTo(const GURL & to_url,CancelableRequestConsumerBase * consumer,QueryRedirectsCallback * callback)586 HistoryService::Handle HistoryService::QueryRedirectsTo(
587     const GURL& to_url,
588     CancelableRequestConsumerBase* consumer,
589     QueryRedirectsCallback* callback) {
590   return Schedule(PRIORITY_NORMAL, &HistoryBackend::QueryRedirectsTo, consumer,
591       new history::QueryRedirectsRequest(callback), to_url);
592 }
593 
GetVisitCountToHost(const GURL & url,CancelableRequestConsumerBase * consumer,GetVisitCountToHostCallback * callback)594 HistoryService::Handle HistoryService::GetVisitCountToHost(
595     const GURL& url,
596     CancelableRequestConsumerBase* consumer,
597     GetVisitCountToHostCallback* callback) {
598   return Schedule(PRIORITY_UI, &HistoryBackend::GetVisitCountToHost, consumer,
599       new history::GetVisitCountToHostRequest(callback), url);
600 }
601 
QueryTopURLsAndRedirects(int result_count,CancelableRequestConsumerBase * consumer,QueryTopURLsAndRedirectsCallback * callback)602 HistoryService::Handle HistoryService::QueryTopURLsAndRedirects(
603     int result_count,
604     CancelableRequestConsumerBase* consumer,
605     QueryTopURLsAndRedirectsCallback* callback) {
606   return Schedule(PRIORITY_NORMAL, &HistoryBackend::QueryTopURLsAndRedirects,
607       consumer, new history::QueryTopURLsAndRedirectsRequest(callback),
608       result_count);
609 }
610 
QueryMostVisitedURLs(int result_count,int days_back,CancelableRequestConsumerBase * consumer,QueryMostVisitedURLsCallback * callback)611 HistoryService::Handle HistoryService::QueryMostVisitedURLs(
612     int result_count,
613     int days_back,
614     CancelableRequestConsumerBase* consumer,
615     QueryMostVisitedURLsCallback* callback) {
616   return Schedule(PRIORITY_NORMAL, &HistoryBackend::QueryMostVisitedURLs,
617                   consumer,
618                   new history::QueryMostVisitedURLsRequest(callback),
619                   result_count, days_back);
620 }
621 
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)622 void HistoryService::Observe(NotificationType type,
623                              const NotificationSource& source,
624                              const NotificationDetails& details) {
625   if (!thread_)
626     return;
627 
628   switch (type.value) {
629     case NotificationType::HISTORY_URLS_DELETED: {
630       // Update the visited link system for deleted URLs. We will update the
631       // visited link system for added URLs as soon as we get the add
632       // notification (we don't have to wait for the backend, which allows us to
633       // be faster to update the state).
634       //
635       // For deleted URLs, we don't typically know what will be deleted since
636       // delete notifications are by time. We would also like to be more
637       // respectful of privacy and never tell the user something is gone when it
638       // isn't. Therefore, we update the delete URLs after the fact.
639       if (!profile_)
640         return;  // No profile, probably unit testing.
641       Details<history::URLsDeletedDetails> deleted_details(details);
642       VisitedLinkMaster* visited_links = profile_->GetVisitedLinkMaster();
643       if (!visited_links)
644         return;  // Nobody to update.
645       if (deleted_details->all_history)
646         visited_links->DeleteAllURLs();
647       else  // Delete individual ones.
648         visited_links->DeleteURLs(deleted_details->urls);
649       break;
650     }
651 
652     case NotificationType::TEMPLATE_URL_REMOVED:
653       DeleteAllSearchTermsForKeyword(*(Details<TemplateURLID>(details).ptr()));
654       break;
655 
656     default:
657       NOTREACHED();
658   }
659 }
660 
Init(const FilePath & history_dir,BookmarkService * bookmark_service,bool no_db)661 bool HistoryService::Init(const FilePath& history_dir,
662                           BookmarkService* bookmark_service,
663                           bool no_db) {
664   if (!thread_->Start()) {
665     Cleanup();
666     return false;
667   }
668 
669   history_dir_ = history_dir;
670   bookmark_service_ = bookmark_service;
671   no_db_ = no_db;
672 
673   // Create the history backend.
674   LoadBackendIfNecessary();
675   return true;
676 }
677 
ScheduleAutocomplete(HistoryURLProvider * provider,HistoryURLProviderParams * params)678 void HistoryService::ScheduleAutocomplete(HistoryURLProvider* provider,
679                                           HistoryURLProviderParams* params) {
680   ScheduleAndForget(PRIORITY_UI, &HistoryBackend::ScheduleAutocomplete,
681                     scoped_refptr<HistoryURLProvider>(provider), params);
682 }
683 
ScheduleTask(SchedulePriority priority,Task * task)684 void HistoryService::ScheduleTask(SchedulePriority priority,
685                                   Task* task) {
686   // TODO(brettw): do prioritization.
687   thread_->message_loop()->PostTask(FROM_HERE, task);
688 }
689 
690 // static
CanAddURL(const GURL & url)691 bool HistoryService::CanAddURL(const GURL& url) {
692   if (!url.is_valid())
693     return false;
694 
695   // TODO: We should allow kChromeUIScheme URLs if they have been explicitly
696   // typed.  Right now, however, these are marked as typed even when triggered
697   // by a shortcut or menu action.
698   if (url.SchemeIs(chrome::kJavaScriptScheme) ||
699       url.SchemeIs(chrome::kChromeDevToolsScheme) ||
700       url.SchemeIs(chrome::kChromeUIScheme) ||
701       url.SchemeIs(chrome::kViewSourceScheme) ||
702       url.SchemeIs(chrome::kChromeInternalScheme))
703     return false;
704 
705   if (url.SchemeIs(chrome::kAboutScheme)) {
706     if (LowerCaseEqualsASCII(url.path(), "blank"))
707       return false;
708     // We allow all other about URLs since the user may like to see things
709     // like "about:memory" or "about:histograms" in their history and
710     // autocomplete.
711   }
712 
713   return true;
714 }
715 
SetInMemoryBackend(history::InMemoryHistoryBackend * mem_backend)716 void HistoryService::SetInMemoryBackend(
717     history::InMemoryHistoryBackend* mem_backend) {
718   DCHECK(!in_memory_backend_.get()) << "Setting mem DB twice";
719   in_memory_backend_.reset(mem_backend);
720 
721   // The database requires additional initialization once we own it.
722   in_memory_backend_->AttachToHistoryService(profile_);
723 }
724 
NotifyProfileError(sql::InitStatus init_status)725 void HistoryService::NotifyProfileError(sql::InitStatus init_status) {
726   ShowProfileErrorDialog(
727       (init_status == sql::INIT_FAILURE) ?
728       IDS_COULDNT_OPEN_PROFILE_ERROR : IDS_PROFILE_TOO_NEW_ERROR);
729 }
730 
DeleteURL(const GURL & url)731 void HistoryService::DeleteURL(const GURL& url) {
732   // We will update the visited links when we observe the delete notifications.
733   ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::DeleteURL, url);
734 }
735 
ExpireHistoryBetween(const std::set<GURL> & restrict_urls,Time begin_time,Time end_time,CancelableRequestConsumerBase * consumer,ExpireHistoryCallback * callback)736 void HistoryService::ExpireHistoryBetween(
737     const std::set<GURL>& restrict_urls,
738     Time begin_time, Time end_time,
739     CancelableRequestConsumerBase* consumer,
740     ExpireHistoryCallback* callback) {
741 
742   // We will update the visited links when we observe the delete notifications.
743   Schedule(PRIORITY_UI, &HistoryBackend::ExpireHistoryBetween, consumer,
744            new history::ExpireHistoryRequest(callback),
745            restrict_urls, begin_time, end_time);
746 }
747 
BroadcastNotifications(NotificationType type,history::HistoryDetails * details_deleted)748 void HistoryService::BroadcastNotifications(
749     NotificationType type,
750     history::HistoryDetails* details_deleted) {
751   // We take ownership of the passed-in pointer and delete it. It was made for
752   // us on another thread, so the caller doesn't know when we will handle it.
753   scoped_ptr<history::HistoryDetails> details(details_deleted);
754   // TODO(evanm): this is currently necessitated by generate_profile, which
755   // runs without a browser process. generate_profile should really create
756   // a browser process, at which point this check can then be nuked.
757   if (!g_browser_process)
758     return;
759 
760   if (!thread_)
761     return;
762 
763   // The source of all of our notifications is the profile. Note that this
764   // pointer is NULL in unit tests.
765   Source<Profile> source(profile_);
766 
767   // The details object just contains the pointer to the object that the
768   // backend has allocated for us. The receiver of the notification will cast
769   // this to the proper type.
770   Details<history::HistoryDetails> det(details_deleted);
771 
772   NotificationService::current()->Notify(type, source, det);
773 }
774 
LoadBackendIfNecessary()775 void HistoryService::LoadBackendIfNecessary() {
776   if (!thread_ || history_backend_)
777     return;  // Failed to init, or already started loading.
778 
779   scoped_refptr<HistoryBackend> backend(
780       new HistoryBackend(history_dir_,
781                          new BackendDelegate(this),
782                          bookmark_service_));
783   history_backend_.swap(backend);
784 
785   // There may not be a profile when unit testing.
786   std::string languages;
787   if (profile_) {
788     PrefService* prefs = profile_->GetPrefs();
789     languages = prefs->GetString(prefs::kAcceptLanguages);
790   }
791   ScheduleAndForget(PRIORITY_UI, &HistoryBackend::Init, languages, no_db_);
792 }
793 
OnDBLoaded()794 void HistoryService::OnDBLoaded() {
795   backend_loaded_ = true;
796   NotificationService::current()->Notify(NotificationType::HISTORY_LOADED,
797                                          Source<Profile>(profile_),
798                                          Details<HistoryService>(this));
799   if (thread_ && profile_) {
800     // We don't want to force creation of TopSites.
801     history::TopSites* ts = profile_->GetTopSitesWithoutCreating();
802     if (ts)
803       ts->HistoryLoaded();
804   }
805 }
806 
StartTopSitesMigration()807 void HistoryService::StartTopSitesMigration() {
808   needs_top_sites_migration_ = true;
809   if (thread_ && profile_) {
810     // We don't want to force creation of TopSites.
811     history::TopSites* ts = profile_->GetTopSitesWithoutCreating();
812     if (ts)
813       ts->MigrateFromHistory();
814   }
815 }
816 
OnTopSitesReady()817 void HistoryService::OnTopSitesReady() {
818   ScheduleAndForget(PRIORITY_NORMAL,
819                     &HistoryBackend::MigrateThumbnailsDatabase);
820 }
821