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
RunWithFaviconResults(const favicon_base::FaviconResultsCallback & callback,std::vector<favicon_base::FaviconRawBitmapResult> * bitmap_results)72 void RunWithFaviconResults(
73 const favicon_base::FaviconResultsCallback& callback,
74 std::vector<favicon_base::FaviconRawBitmapResult>* bitmap_results) {
75 callback.Run(*bitmap_results);
76 }
77
RunWithFaviconResult(const favicon_base::FaviconRawBitmapCallback & callback,favicon_base::FaviconRawBitmapResult * bitmap_result)78 void RunWithFaviconResult(
79 const favicon_base::FaviconRawBitmapCallback& callback,
80 favicon_base::FaviconRawBitmapResult* bitmap_result) {
81 callback.Run(*bitmap_result);
82 }
83
RunWithQueryURLResult(const HistoryService::QueryURLCallback & callback,const HistoryBackend::QueryURLResult * result)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:
URLIteratorFromURLRows(const history::URLRows & url_rows)93 explicit URLIteratorFromURLRows(const history::URLRows& url_rows)
94 : itr_(url_rows.begin()),
95 end_(url_rows.end()) {
96 }
97
NextURL()98 virtual const GURL& NextURL() OVERRIDE {
99 return (itr_++)->url();
100 }
101
HasNextURL() const102 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().
ExpireWebHistoryComplete(bool success)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:
BackendDelegate(const base::WeakPtr<HistoryService> & history_service,const scoped_refptr<base::SequencedTaskRunner> & service_task_runner,Profile * profile)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
NotifyProfileError(sql::InitStatus init_status)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
SetInMemoryBackend(scoped_ptr<history::InMemoryHistoryBackend> backend)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
BroadcastNotifications(int type,scoped_ptr<history::HistoryDetails> details)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
DBLoaded()171 virtual void DBLoaded() OVERRIDE {
172 service_task_runner_->PostTask(
173 FROM_HERE,
174 base::Bind(&HistoryService::OnDBLoaded, history_service_));
175 }
176
NotifyVisitDBObserversOnAddVisit(const history::BriefVisitInfo & info)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.
HistoryService()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
HistoryService(history::HistoryClient * client,Profile * profile)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
~HistoryService()219 HistoryService::~HistoryService() {
220 DCHECK(thread_checker_.CalledOnValidThread());
221 // Shutdown the backend. This does nothing if Cleanup was already invoked.
222 Cleanup();
223 }
224
BackendLoaded()225 bool HistoryService::BackendLoaded() {
226 DCHECK(thread_checker_.CalledOnValidThread());
227 return backend_loaded_;
228 }
229
Cleanup()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
ClearCachedDataForContextID(history::ContextID context_id)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
InMemoryDatabase()294 history::URLDatabase* HistoryService::InMemoryDatabase() {
295 DCHECK(thread_checker_.CalledOnValidThread());
296 return in_memory_backend_ ? in_memory_backend_->db() : NULL;
297 }
298
GetTypedCountForURL(const GURL & url,int * typed_count)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
GetLastVisitTimeForURL(const GURL & url,base::Time * last_visit)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
GetVisitCountForURL(const GURL & url,int * visit_count)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
GetTypedUrlSyncableService() const327 history::TypedUrlSyncableService* HistoryService::GetTypedUrlSyncableService()
328 const {
329 return history_backend_->GetTypedUrlSyncableService();
330 }
331
Shutdown()332 void HistoryService::Shutdown() {
333 DCHECK(thread_checker_.CalledOnValidThread());
334 Cleanup();
335 }
336
SetKeywordSearchTermsForURL(const GURL & url,TemplateURLID keyword_id,const base::string16 & term)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
DeleteAllSearchTermsForKeyword(TemplateURLID keyword_id)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
GetMostRecentKeywordSearchTerms(TemplateURLID keyword_id,const base::string16 & prefix,int max_count,CancelableRequestConsumerBase * consumer,const GetMostRecentKeywordSearchTermsCallback & callback)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
DeleteKeywordSearchTermForURL(const GURL & url)367 void HistoryService::DeleteKeywordSearchTermForURL(const GURL& url) {
368 DCHECK(thread_checker_.CalledOnValidThread());
369 ScheduleAndForget(PRIORITY_UI, &HistoryBackend::DeleteKeywordSearchTermForURL,
370 url);
371 }
372
DeleteMatchingURLsForKeyword(TemplateURLID keyword_id,const base::string16 & term)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
URLsNoLongerBookmarked(const std::set<GURL> & urls)380 void HistoryService::URLsNoLongerBookmarked(const std::set<GURL>& urls) {
381 DCHECK(thread_checker_.CalledOnValidThread());
382 ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::URLsNoLongerBookmarked,
383 urls);
384 }
385
ScheduleDBTask(history::HistoryDBTask * task,CancelableRequestConsumerBase * consumer)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
QuerySegmentUsageSince(CancelableRequestConsumerBase * consumer,const Time from_time,int max_result_count,const SegmentQueryCallback & callback)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
FlushForTest(const base::Closure & flushed)406 void HistoryService::FlushForTest(const base::Closure& flushed) {
407 thread_->message_loop_proxy()->PostTaskAndReply(
408 FROM_HERE, base::Bind(&base::DoNothing), flushed);
409 }
410
SetOnBackendDestroyTask(const base::Closure & task)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
AddPage(const GURL & url,Time time,history::ContextID context_id,int32 page_id,const GURL & referrer,const history::RedirectList & redirects,content::PageTransition transition,history::VisitSource visit_source,bool did_replace_entry)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
AddPage(const GURL & url,base::Time time,history::VisitSource visit_source)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
AddPage(const history::HistoryAddPageArgs & add_page_args)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
AddPageNoVisitForBookmark(const GURL & url,const base::string16 & title)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
SetPageTitle(const GURL & url,const base::string16 & title)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
UpdateWithPageEndTime(history::ContextID context_id,int32 page_id,const GURL & url,Time end_ts)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
AddPageWithDetails(const GURL & url,const base::string16 & title,int visit_count,int typed_count,Time last_visit,bool hidden,history::VisitSource visit_source)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
AddPagesWithDetails(const history::URLRows & info,history::VisitSource visit_source)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
GetFavicons(const std::vector<GURL> & icon_urls,int icon_types,const std::vector<int> & desired_sizes,const favicon_base::FaviconResultsCallback & callback,base::CancelableTaskTracker * tracker)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
GetFaviconsForURL(const GURL & page_url,int icon_types,const std::vector<int> & desired_sizes,const favicon_base::FaviconResultsCallback & callback,base::CancelableTaskTracker * tracker)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
GetLargestFaviconForURL(const GURL & page_url,const std::vector<int> & icon_types,int minimum_size_in_pixels,const favicon_base::FaviconRawBitmapCallback & callback,base::CancelableTaskTracker * tracker)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
GetFaviconForID(favicon_base::FaviconID favicon_id,int desired_size,const favicon_base::FaviconResultsCallback & callback,base::CancelableTaskTracker * tracker)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
UpdateFaviconMappingsAndFetch(const GURL & page_url,const std::vector<GURL> & icon_urls,int icon_types,const std::vector<int> & desired_sizes,const favicon_base::FaviconResultsCallback & callback,base::CancelableTaskTracker * tracker)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
MergeFavicon(const GURL & page_url,const GURL & icon_url,favicon_base::IconType icon_type,scoped_refptr<base::RefCountedMemory> bitmap_data,const gfx::Size & pixel_size)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
SetFavicons(const GURL & page_url,favicon_base::IconType icon_type,const std::vector<favicon_base::FaviconRawBitmapData> & favicon_bitmap_data)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
SetFaviconsOutOfDateForPage(const GURL & page_url)685 void HistoryService::SetFaviconsOutOfDateForPage(const GURL& page_url) {
686 DCHECK(thread_checker_.CalledOnValidThread());
687 ScheduleAndForget(PRIORITY_NORMAL,
688 &HistoryBackend::SetFaviconsOutOfDateForPage, page_url);
689 }
690
CloneFavicons(const GURL & old_page_url,const GURL & new_page_url)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
SetImportedFavicons(const std::vector<ImportedFaviconUsage> & favicon_usage)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
QueryURL(const GURL & url,bool want_visits,const QueryURLCallback & callback,base::CancelableTaskTracker * tracker)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.
CreateDownload(const history::DownloadRow & create_info,const HistoryService::DownloadCreateCallback & callback)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
GetNextDownloadId(const content::DownloadIdCallback & callback)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.
QueryDownloads(const DownloadQueryCallback & callback)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.
UpdateDownload(const history::DownloadRow & data)772 void HistoryService::UpdateDownload(const history::DownloadRow& data) {
773 DCHECK(thread_checker_.CalledOnValidThread());
774 ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::UpdateDownload, data);
775 }
776
RemoveDownloads(const std::set<uint32> & ids)777 void HistoryService::RemoveDownloads(const std::set<uint32>& ids) {
778 DCHECK(thread_checker_.CalledOnValidThread());
779 ScheduleAndForget(PRIORITY_NORMAL,
780 &HistoryBackend::RemoveDownloads, ids);
781 }
782
QueryHistory(const base::string16 & text_query,const history::QueryOptions & options,CancelableRequestConsumerBase * consumer,const QueryHistoryCallback & callback)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
QueryRedirectsFrom(const GURL & from_url,CancelableRequestConsumerBase * consumer,const QueryRedirectsCallback & callback)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
QueryRedirectsTo(const GURL & to_url,CancelableRequestConsumerBase * consumer,const QueryRedirectsCallback & callback)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
GetVisibleVisitCountToHost(const GURL & url,CancelableRequestConsumerBase * consumer,const GetVisibleVisitCountToHostCallback & callback)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
QueryTopURLsAndRedirects(int result_count,CancelableRequestConsumerBase * consumer,const QueryTopURLsAndRedirectsCallback & callback)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
QueryMostVisitedURLs(int result_count,int days_back,CancelableRequestConsumerBase * consumer,const QueryMostVisitedURLsCallback & callback)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
QueryFilteredURLs(int result_count,const history::VisitFilter & filter,bool extended_info,CancelableRequestConsumerBase * consumer,const QueryFilteredURLsCallback & callback)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
Observe(int type,const content::NotificationSource & source,const content::NotificationDetails & details)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
RebuildTable(const scoped_refptr<URLEnumerator> & enumerator)898 void HistoryService::RebuildTable(
899 const scoped_refptr<URLEnumerator>& enumerator) {
900 DCHECK(thread_checker_.CalledOnValidThread());
901 ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::IterateURLs, enumerator);
902 }
903
Init(const base::FilePath & history_dir,bool no_db)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
ScheduleAutocomplete(HistoryURLProvider * provider,HistoryURLProviderParams * params)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
ScheduleTask(SchedulePriority priority,const base::Closure & task)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
CanAddURL(const GURL & url)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
AsWeakPtr()989 base::WeakPtr<HistoryService> HistoryService::AsWeakPtr() {
990 DCHECK(thread_checker_.CalledOnValidThread());
991 return weak_ptr_factory_.GetWeakPtr();
992 }
993
MergeDataAndStartSyncing(syncer::ModelType type,const syncer::SyncDataList & initial_sync_data,scoped_ptr<syncer::SyncChangeProcessor> sync_processor,scoped_ptr<syncer::SyncErrorFactory> error_handler)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
StopSyncing(syncer::ModelType type)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
GetAllSyncData(syncer::ModelType type) const1012 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
ProcessSyncChanges(const tracked_objects::Location & from_here,const syncer::SyncChangeList & change_list)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
ProcessLocalDeleteDirective(const sync_pb::HistoryDeleteDirectiveSpecifics & delete_directive)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
SetInMemoryBackend(scoped_ptr<history::InMemoryHistoryBackend> mem_backend)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
NotifyProfileError(sql::InitStatus init_status)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
DeleteURL(const GURL & url)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
DeleteURLsForTest(const std::vector<GURL> & urls)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
ExpireHistoryBetween(const std::set<GURL> & restrict_urls,Time begin_time,Time end_time,const base::Closure & callback,base::CancelableTaskTracker * tracker)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
ExpireHistory(const std::vector<history::ExpireHistoryArgs> & expire_list,const base::Closure & callback,base::CancelableTaskTracker * tracker)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
ExpireLocalAndRemoteHistoryBetween(const std::set<GURL> & restrict_urls,Time begin_time,Time end_time,const base::Closure & callback,base::CancelableTaskTracker * tracker)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
BroadcastNotificationsHelper(int type,scoped_ptr<history::HistoryDetails> details)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
OnDBLoaded()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
GetRowForURL(const GURL & url,history::URLRow * url_row)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
AddVisitDatabaseObserver(history::VisitDatabaseObserver * observer)1166 void HistoryService::AddVisitDatabaseObserver(
1167 history::VisitDatabaseObserver* observer) {
1168 DCHECK(thread_checker_.CalledOnValidThread());
1169 visit_database_observers_.AddObserver(observer);
1170 }
1171
RemoveVisitDatabaseObserver(history::VisitDatabaseObserver * observer)1172 void HistoryService::RemoveVisitDatabaseObserver(
1173 history::VisitDatabaseObserver* observer) {
1174 DCHECK(thread_checker_.CalledOnValidThread());
1175 visit_database_observers_.RemoveObserver(observer);
1176 }
1177
NotifyVisitDBObserversOnAddVisit(const history::BriefVisitInfo & info)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 }
1184