- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / history / history_backend.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 #include "chrome/browser/history/history_backend.h"
6
7 #include <algorithm>
8 #include <functional>
9 #include <list>
10 #include <map>
11 #include <set>
12 #include <vector>
13
14 #include "base/basictypes.h"
15 #include "base/bind.h"
16 #include "base/compiler_specific.h"
17 #include "base/files/file_enumerator.h"
18 #include "base/memory/scoped_ptr.h"
19 #include "base/memory/scoped_vector.h"
20 #include "base/message_loop/message_loop.h"
21 #include "base/metrics/histogram.h"
22 #include "base/rand_util.h"
23 #include "base/strings/string_util.h"
24 #include "base/strings/utf_string_conversions.h"
25 #include "base/time/time.h"
26 #include "chrome/browser/autocomplete/history_url_provider.h"
27 #include "chrome/browser/bookmarks/bookmark_service.h"
28 #include "chrome/browser/chrome_notification_types.h"
29 #include "chrome/browser/favicon/favicon_changed_details.h"
30 #include "chrome/browser/history/download_row.h"
31 #include "chrome/browser/history/history_db_task.h"
32 #include "chrome/browser/history/history_notifications.h"
33 #include "chrome/browser/history/history_publisher.h"
34 #include "chrome/browser/history/in_memory_history_backend.h"
35 #include "chrome/browser/history/page_collector.h"
36 #include "chrome/browser/history/page_usage_data.h"
37 #include "chrome/browser/history/select_favicon_frames.h"
38 #include "chrome/browser/history/top_sites.h"
39 #include "chrome/browser/history/typed_url_syncable_service.h"
40 #include "chrome/browser/history/visit_filter.h"
41 #include "chrome/common/chrome_constants.h"
42 #include "chrome/common/importer/imported_favicon_usage.h"
43 #include "chrome/common/url_constants.h"
44 #include "grit/chromium_strings.h"
45 #include "grit/generated_resources.h"
46 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
47 #include "sql/error_delegate_util.h"
48 #include "url/gurl.h"
49
50 #if defined(OS_ANDROID)
51 #include "chrome/browser/history/android/android_provider_backend.h"
52 #endif
53
54 using base::Time;
55 using base::TimeDelta;
56 using base::TimeTicks;
57
58 /* The HistoryBackend consists of a number of components:
59
60     HistoryDatabase (stores past 3 months of history)
61       URLDatabase (stores a list of URLs)
62       DownloadDatabase (stores a list of downloads)
63       VisitDatabase (stores a list of visits for the URLs)
64       VisitSegmentDatabase (stores groups of URLs for the most visited view).
65
66     ArchivedDatabase (stores history older than 3 months)
67       URLDatabase (stores a list of URLs)
68       DownloadDatabase (stores a list of downloads)
69       VisitDatabase (stores a list of visits for the URLs)
70
71       (this does not store visit segments as they expire after 3 mos.)
72
73     ExpireHistoryBackend (manages moving things from HistoryDatabase to
74                           the ArchivedDatabase and deleting)
75 */
76
77 namespace history {
78
79 // How long we keep segment data for in days. Currently 3 months.
80 // This value needs to be greater or equal to
81 // MostVisitedModel::kMostVisitedScope but we don't want to introduce a direct
82 // dependency between MostVisitedModel and the history backend.
83 const int kSegmentDataRetention = 90;
84
85 // How long we'll wait to do a commit, so that things are batched together.
86 const int kCommitIntervalSeconds = 10;
87
88 // The amount of time before we re-fetch the favicon.
89 const int kFaviconRefetchDays = 7;
90
91 // The maximum number of items we'll allow in the redirect list before
92 // deleting some.
93 const int kMaxRedirectCount = 32;
94
95 // The number of days old a history entry can be before it is considered "old"
96 // and is archived.
97 const int kArchiveDaysThreshold = 90;
98
99 #if defined(OS_ANDROID)
100 // The maximum number of top sites to track when recording top page visit stats.
101 const size_t kPageVisitStatsMaxTopSites = 50;
102 #endif
103
104 // Converts from PageUsageData to MostVisitedURL. |redirects| is a
105 // list of redirects for this URL. Empty list means no redirects.
106 MostVisitedURL MakeMostVisitedURL(const PageUsageData& page_data,
107                                   const RedirectList& redirects) {
108   MostVisitedURL mv;
109   mv.url = page_data.GetURL();
110   mv.title = page_data.GetTitle();
111   if (redirects.empty()) {
112     // Redirects must contain at least the target url.
113     mv.redirects.push_back(mv.url);
114   } else {
115     mv.redirects = redirects;
116     if (mv.redirects[mv.redirects.size() - 1] != mv.url) {
117       // The last url must be the target url.
118       mv.redirects.push_back(mv.url);
119     }
120   }
121   return mv;
122 }
123
124 // This task is run on a timer so that commits happen at regular intervals
125 // so they are batched together. The important thing about this class is that
126 // it supports canceling of the task so the reference to the backend will be
127 // freed. The problem is that when history is shutting down, there is likely
128 // to be one of these commits still pending and holding a reference.
129 //
130 // The backend can call Cancel to have this task release the reference. The
131 // task will still run (if we ever get to processing the event before
132 // shutdown), but it will not do anything.
133 //
134 // Note that this is a refcounted object and is not a task in itself. It should
135 // be assigned to a RunnableMethod.
136 //
137 // TODO(brettw): bug 1165182: This should be replaced with a
138 // base::WeakPtrFactory which will handle everything automatically (like we do
139 // in ExpireHistoryBackend).
140 class CommitLaterTask : public base::RefCounted<CommitLaterTask> {
141  public:
142   explicit CommitLaterTask(HistoryBackend* history_backend)
143       : history_backend_(history_backend) {
144   }
145
146   // The backend will call this function if it is being destroyed so that we
147   // release our reference.
148   void Cancel() {
149     history_backend_ = NULL;
150   }
151
152   void RunCommit() {
153     if (history_backend_.get())
154       history_backend_->Commit();
155   }
156
157  private:
158   friend class base::RefCounted<CommitLaterTask>;
159
160   ~CommitLaterTask() {}
161
162   scoped_refptr<HistoryBackend> history_backend_;
163 };
164
165 // HistoryBackend --------------------------------------------------------------
166
167 HistoryBackend::HistoryBackend(const base::FilePath& history_dir,
168                                int id,
169                                Delegate* delegate,
170                                BookmarkService* bookmark_service)
171     : delegate_(delegate),
172       id_(id),
173       history_dir_(history_dir),
174       scheduled_kill_db_(false),
175       expirer_(this, bookmark_service),
176       recent_redirects_(kMaxRedirectCount),
177       backend_destroy_message_loop_(NULL),
178       segment_queried_(false),
179       bookmark_service_(bookmark_service) {
180 }
181
182 HistoryBackend::~HistoryBackend() {
183   DCHECK(!scheduled_commit_.get()) << "Deleting without cleanup";
184   ReleaseDBTasks();
185
186 #if defined(OS_ANDROID)
187   // Release AndroidProviderBackend before other objects.
188   android_provider_backend_.reset();
189 #endif
190
191   // First close the databases before optionally running the "destroy" task.
192   CloseAllDatabases();
193
194   if (!backend_destroy_task_.is_null()) {
195     // Notify an interested party (typically a unit test) that we're done.
196     DCHECK(backend_destroy_message_loop_);
197     backend_destroy_message_loop_->PostTask(FROM_HERE, backend_destroy_task_);
198   }
199
200 #if defined(OS_ANDROID)
201   sql::Connection::Delete(GetAndroidCacheFileName());
202 #endif
203 }
204
205 void HistoryBackend::Init(const std::string& languages, bool force_fail) {
206   if (!force_fail)
207     InitImpl(languages);
208   delegate_->DBLoaded(id_);
209   typed_url_syncable_service_.reset(new TypedUrlSyncableService(this));
210   memory_pressure_listener_.reset(new base::MemoryPressureListener(
211       base::Bind(&HistoryBackend::OnMemoryPressure, base::Unretained(this))));
212 #if defined(OS_ANDROID)
213   PopulateMostVisitedURLMap();
214 #endif
215 }
216
217 void HistoryBackend::SetOnBackendDestroyTask(base::MessageLoop* message_loop,
218                                              const base::Closure& task) {
219   if (!backend_destroy_task_.is_null())
220     DLOG(WARNING) << "Setting more than one destroy task, overriding";
221   backend_destroy_message_loop_ = message_loop;
222   backend_destroy_task_ = task;
223 }
224
225 void HistoryBackend::Closing() {
226   // Any scheduled commit will have a reference to us, we must make it
227   // release that reference before we can be destroyed.
228   CancelScheduledCommit();
229
230   // Release our reference to the delegate, this reference will be keeping the
231   // history service alive.
232   delegate_.reset();
233 }
234
235 void HistoryBackend::NotifyRenderProcessHostDestruction(const void* host) {
236   tracker_.NotifyRenderProcessHostDestruction(host);
237 }
238
239 base::FilePath HistoryBackend::GetThumbnailFileName() const {
240   return history_dir_.Append(chrome::kThumbnailsFilename);
241 }
242
243 base::FilePath HistoryBackend::GetFaviconsFileName() const {
244   return history_dir_.Append(chrome::kFaviconsFilename);
245 }
246
247 base::FilePath HistoryBackend::GetArchivedFileName() const {
248   return history_dir_.Append(chrome::kArchivedHistoryFilename);
249 }
250
251 #if defined(OS_ANDROID)
252 base::FilePath HistoryBackend::GetAndroidCacheFileName() const {
253   return history_dir_.Append(chrome::kAndroidCacheFilename);
254 }
255 #endif
256
257 SegmentID HistoryBackend::GetLastSegmentID(VisitID from_visit) {
258   // Set is used to detect referrer loops.  Should not happen, but can
259   // if the database is corrupt.
260   std::set<VisitID> visit_set;
261   VisitID visit_id = from_visit;
262   while (visit_id) {
263     VisitRow row;
264     if (!db_->GetRowForVisit(visit_id, &row))
265       return 0;
266     if (row.segment_id)
267       return row.segment_id;  // Found a visit in this change with a segment.
268
269     // Check the referrer of this visit, if any.
270     visit_id = row.referring_visit;
271
272     if (visit_set.find(visit_id) != visit_set.end()) {
273       NOTREACHED() << "Loop in referer chain, giving up";
274       break;
275     }
276     visit_set.insert(visit_id);
277   }
278   return 0;
279 }
280
281 SegmentID HistoryBackend::UpdateSegments(
282     const GURL& url,
283     VisitID from_visit,
284     VisitID visit_id,
285     content::PageTransition transition_type,
286     const Time ts) {
287   if (!db_)
288     return 0;
289
290   // We only consider main frames.
291   if (!content::PageTransitionIsMainFrame(transition_type))
292     return 0;
293
294   SegmentID segment_id = 0;
295   content::PageTransition t =
296       content::PageTransitionStripQualifier(transition_type);
297
298   // Are we at the beginning of a new segment?
299   // Note that navigating to an existing entry (with back/forward) reuses the
300   // same transition type.  We are not adding it as a new segment in that case
301   // because if this was the target of a redirect, we might end up with
302   // 2 entries for the same final URL. Ex: User types google.net, gets
303   // redirected to google.com. A segment is created for google.net. On
304   // google.com users navigates through a link, then press back. That last
305   // navigation is for the entry google.com transition typed. We end up adding
306   // a segment for that one as well. So we end up with google.net and google.com
307   // in the segment table, showing as 2 entries in the NTP.
308   // Note also that we should still be updating the visit count for that segment
309   // which we are not doing now. It should be addressed when
310   // http://crbug.com/96860 is fixed.
311   if ((t == content::PAGE_TRANSITION_TYPED ||
312        t == content::PAGE_TRANSITION_AUTO_BOOKMARK) &&
313       (transition_type & content::PAGE_TRANSITION_FORWARD_BACK) == 0) {
314     // If so, create or get the segment.
315     std::string segment_name = db_->ComputeSegmentName(url);
316     URLID url_id = db_->GetRowForURL(url, NULL);
317     if (!url_id)
318       return 0;
319
320     if (!(segment_id = db_->GetSegmentNamed(segment_name))) {
321       if (!(segment_id = db_->CreateSegment(url_id, segment_name))) {
322         NOTREACHED();
323         return 0;
324       }
325     } else {
326       // Note: if we update an existing segment, we update the url used to
327       // represent that segment in order to minimize stale most visited
328       // images.
329       db_->UpdateSegmentRepresentationURL(segment_id, url_id);
330     }
331   } else {
332     // Note: it is possible there is no segment ID set for this visit chain.
333     // This can happen if the initial navigation wasn't AUTO_BOOKMARK or
334     // TYPED. (For example GENERATED). In this case this visit doesn't count
335     // toward any segment.
336     if (!(segment_id = GetLastSegmentID(from_visit)))
337       return 0;
338   }
339
340   // Set the segment in the visit.
341   if (!db_->SetSegmentID(visit_id, segment_id)) {
342     NOTREACHED();
343     return 0;
344   }
345
346   // Finally, increase the counter for that segment / day.
347   if (!db_->IncreaseSegmentVisitCount(segment_id, ts, 1)) {
348     NOTREACHED();
349     return 0;
350   }
351   return segment_id;
352 }
353
354 void HistoryBackend::UpdateWithPageEndTime(const void* host,
355                                            int32 page_id,
356                                            const GURL& url,
357                                            Time end_ts) {
358   // Will be filled with the URL ID and the visit ID of the last addition.
359   VisitID visit_id = tracker_.GetLastVisit(host, page_id, url);
360   UpdateVisitDuration(visit_id, end_ts);
361 }
362
363 void HistoryBackend::UpdateVisitDuration(VisitID visit_id, const Time end_ts) {
364   if (!db_)
365     return;
366
367   // Get the starting visit_time for visit_id.
368   VisitRow visit_row;
369   if (db_->GetRowForVisit(visit_id, &visit_row)) {
370     // We should never have a negative duration time even when time is skewed.
371     visit_row.visit_duration = end_ts > visit_row.visit_time ?
372         end_ts - visit_row.visit_time : TimeDelta::FromMicroseconds(0);
373     db_->UpdateVisitRow(visit_row);
374   }
375 }
376
377 void HistoryBackend::AddPage(const HistoryAddPageArgs& request) {
378   if (!db_)
379     return;
380
381   // Will be filled with the URL ID and the visit ID of the last addition.
382   std::pair<URLID, VisitID> last_ids(0, tracker_.GetLastVisit(
383       request.id_scope, request.page_id, request.referrer));
384
385   VisitID from_visit_id = last_ids.second;
386
387   // If a redirect chain is given, we expect the last item in that chain to be
388   // the final URL.
389   DCHECK(request.redirects.empty() ||
390          request.redirects.back() == request.url);
391
392   // If the user is adding older history, we need to make sure our times
393   // are correct.
394   if (request.time < first_recorded_time_)
395     first_recorded_time_ = request.time;
396
397   content::PageTransition request_transition = request.transition;
398   content::PageTransition stripped_transition =
399     content::PageTransitionStripQualifier(request_transition);
400   bool is_keyword_generated =
401       (stripped_transition == content::PAGE_TRANSITION_KEYWORD_GENERATED);
402
403   // If the user is navigating to a not-previously-typed intranet hostname,
404   // change the transition to TYPED so that the omnibox will learn that this is
405   // a known host.
406   bool has_redirects = request.redirects.size() > 1;
407   if (content::PageTransitionIsMainFrame(request_transition) &&
408       (stripped_transition != content::PAGE_TRANSITION_TYPED) &&
409       !is_keyword_generated) {
410     const GURL& origin_url(has_redirects ?
411         request.redirects[0] : request.url);
412     if (origin_url.SchemeIs(content::kHttpScheme) ||
413         origin_url.SchemeIs(content::kHttpsScheme) ||
414         origin_url.SchemeIs(chrome::kFtpScheme)) {
415       std::string host(origin_url.host());
416       size_t registry_length =
417           net::registry_controlled_domains::GetRegistryLength(
418               host,
419               net::registry_controlled_domains::EXCLUDE_UNKNOWN_REGISTRIES,
420               net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES);
421       if (registry_length == 0 && !db_->IsTypedHost(host)) {
422         stripped_transition = content::PAGE_TRANSITION_TYPED;
423         request_transition =
424             content::PageTransitionFromInt(
425                 stripped_transition |
426                 content::PageTransitionGetQualifier(request_transition));
427       }
428     }
429   }
430
431   if (!has_redirects) {
432     // The single entry is both a chain start and end.
433     content::PageTransition t = content::PageTransitionFromInt(
434         request_transition |
435         content::PAGE_TRANSITION_CHAIN_START |
436         content::PAGE_TRANSITION_CHAIN_END);
437
438     // No redirect case (one element means just the page itself).
439     last_ids = AddPageVisit(request.url, request.time,
440                             last_ids.second, t, request.visit_source);
441
442     // Update the segment for this visit. KEYWORD_GENERATED visits should not
443     // result in changing most visited, so we don't update segments (most
444     // visited db).
445     if (!is_keyword_generated) {
446       UpdateSegments(request.url, from_visit_id, last_ids.second, t,
447                      request.time);
448
449       // Update the referrer's duration.
450       UpdateVisitDuration(from_visit_id, request.time);
451     }
452   } else {
453     // Redirect case. Add the redirect chain.
454
455     content::PageTransition redirect_info =
456         content::PAGE_TRANSITION_CHAIN_START;
457
458     RedirectList redirects = request.redirects;
459     if (redirects[0].SchemeIs(chrome::kAboutScheme)) {
460       // When the redirect source + referrer is "about" we skip it. This
461       // happens when a page opens a new frame/window to about:blank and then
462       // script sets the URL to somewhere else (used to hide the referrer). It
463       // would be nice to keep all these redirects properly but we don't ever
464       // see the initial about:blank load, so we don't know where the
465       // subsequent client redirect came from.
466       //
467       // In this case, we just don't bother hooking up the source of the
468       // redirects, so we remove it.
469       redirects.erase(redirects.begin());
470     } else if (request_transition & content::PAGE_TRANSITION_CLIENT_REDIRECT) {
471       redirect_info = content::PAGE_TRANSITION_CLIENT_REDIRECT;
472       // The first entry in the redirect chain initiated a client redirect.
473       // We don't add this to the database since the referrer is already
474       // there, so we skip over it but change the transition type of the first
475       // transition to client redirect.
476       //
477       // The referrer is invalid when restoring a session that features an
478       // https tab that redirects to a different host or to http. In this
479       // case we don't need to reconnect the new redirect with the existing
480       // chain.
481       if (request.referrer.is_valid()) {
482         DCHECK(request.referrer == redirects[0]);
483         redirects.erase(redirects.begin());
484
485         // If the navigation entry for this visit has replaced that for the
486         // first visit, remove the CHAIN_END marker from the first visit. This
487         // can be called a lot, for example, the page cycler, and most of the
488         // time we won't have changed anything.
489         VisitRow visit_row;
490         if (request.did_replace_entry &&
491             db_->GetRowForVisit(last_ids.second, &visit_row) &&
492             visit_row.transition & content::PAGE_TRANSITION_CHAIN_END) {
493           visit_row.transition = content::PageTransitionFromInt(
494               visit_row.transition & ~content::PAGE_TRANSITION_CHAIN_END);
495           db_->UpdateVisitRow(visit_row);
496         }
497       }
498     }
499
500     for (size_t redirect_index = 0; redirect_index < redirects.size();
501          redirect_index++) {
502       content::PageTransition t =
503           content::PageTransitionFromInt(stripped_transition | redirect_info);
504
505       // If this is the last transition, add a CHAIN_END marker
506       if (redirect_index == (redirects.size() - 1)) {
507         t = content::PageTransitionFromInt(
508             t | content::PAGE_TRANSITION_CHAIN_END);
509       }
510
511       // Record all redirect visits with the same timestamp. We don't display
512       // them anyway, and if we ever decide to, we can reconstruct their order
513       // from the redirect chain.
514       last_ids = AddPageVisit(redirects[redirect_index],
515                               request.time, last_ids.second,
516                               t, request.visit_source);
517       if (t & content::PAGE_TRANSITION_CHAIN_START) {
518         // Update the segment for this visit.
519         UpdateSegments(redirects[redirect_index],
520                        from_visit_id, last_ids.second, t, request.time);
521
522         // Update the visit_details for this visit.
523         UpdateVisitDuration(from_visit_id, request.time);
524       }
525
526       // Subsequent transitions in the redirect list must all be server
527       // redirects.
528       redirect_info = content::PAGE_TRANSITION_SERVER_REDIRECT;
529     }
530
531     // Last, save this redirect chain for later so we can set titles & favicons
532     // on the redirected pages properly.
533     recent_redirects_.Put(request.url, redirects);
534   }
535
536   // TODO(brettw) bug 1140015: Add an "add page" notification so the history
537   // views can keep in sync.
538
539   // Add the last visit to the tracker so we can get outgoing transitions.
540   // TODO(evanm): Due to http://b/1194536 we lose the referrers of a subframe
541   // navigation anyway, so last_visit_id is always zero for them.  But adding
542   // them here confuses main frame history, so we skip them for now.
543   if (stripped_transition != content::PAGE_TRANSITION_AUTO_SUBFRAME &&
544       stripped_transition != content::PAGE_TRANSITION_MANUAL_SUBFRAME &&
545       !is_keyword_generated) {
546     tracker_.AddVisit(request.id_scope, request.page_id, request.url,
547                       last_ids.second);
548   }
549
550   if (page_collector_)
551     page_collector_->AddPageURL(request.url, request.time);
552
553   ScheduleCommit();
554 }
555
556 void HistoryBackend::InitImpl(const std::string& languages) {
557   DCHECK(!db_) << "Initializing HistoryBackend twice";
558   // In the rare case where the db fails to initialize a dialog may get shown
559   // the blocks the caller, yet allows other messages through. For this reason
560   // we only set db_ to the created database if creation is successful. That
561   // way other methods won't do anything as db_ is still NULL.
562
563   TimeTicks beginning_time = TimeTicks::Now();
564
565   // Compute the file names.
566   base::FilePath history_name = history_dir_.Append(chrome::kHistoryFilename);
567   base::FilePath thumbnail_name = GetFaviconsFileName();
568   base::FilePath archived_name = GetArchivedFileName();
569
570   // Delete the old index database files which are no longer used.
571   DeleteFTSIndexDatabases();
572
573   // History database.
574   db_.reset(new HistoryDatabase());
575
576   // Unretained to avoid a ref loop with db_.
577   db_->set_error_callback(
578       base::Bind(&HistoryBackend::DatabaseErrorCallback,
579                  base::Unretained(this)));
580
581   sql::InitStatus status = db_->Init(history_name);
582   switch (status) {
583     case sql::INIT_OK:
584       break;
585     case sql::INIT_FAILURE: {
586       // A NULL db_ will cause all calls on this object to notice this error
587       // and to not continue. If the error callback scheduled killing the
588       // database, the task it posted has not executed yet. Try killing the
589       // database now before we close it.
590       bool kill_db = scheduled_kill_db_;
591       if (kill_db)
592         KillHistoryDatabase();
593       UMA_HISTOGRAM_BOOLEAN("History.AttemptedToFixProfileError", kill_db);
594       delegate_->NotifyProfileError(id_, status);
595       db_.reset();
596       return;
597     }
598     default:
599       NOTREACHED();
600   }
601
602   // Fill the in-memory database and send it back to the history service on the
603   // main thread.
604   InMemoryHistoryBackend* mem_backend = new InMemoryHistoryBackend;
605   if (mem_backend->Init(history_name, db_.get()))
606     delegate_->SetInMemoryBackend(id_, mem_backend);  // Takes ownership of
607                                                       // pointer.
608   else
609     delete mem_backend;  // Error case, run without the in-memory DB.
610   db_->BeginExclusiveMode();  // Must be after the mem backend read the data.
611
612   // Create the history publisher which needs to be passed on to the thumbnail
613   // database for publishing history.
614   // TODO(shess): HistoryPublisher is being deprecated.  I am still
615   // trying to track down who depends on it, meanwhile talk to me
616   // before removing interactions with it.  http://crbug.com/294306
617   history_publisher_.reset(new HistoryPublisher());
618   if (!history_publisher_->Init()) {
619     // The init may fail when there are no indexers wanting our history.
620     // Hence no need to log the failure.
621     history_publisher_.reset();
622   }
623
624   // Collects page data for history_publisher_.
625   if (history_publisher_.get()) {
626     page_collector_.reset(new PageCollector());
627     page_collector_->Init(history_publisher_.get());
628   }
629
630   // Thumbnail database.
631   // TODO(shess): "thumbnail database" these days only stores
632   // favicons.  Thumbnails are stored in "top sites".  Consider
633   // renaming "thumbnail" references to "favicons" or something of the
634   // sort.
635   thumbnail_db_.reset(new ThumbnailDatabase());
636   if (thumbnail_db_->Init(thumbnail_name) != sql::INIT_OK) {
637     // Unlike the main database, we don't error out when the database is too
638     // new because this error is much less severe. Generally, this shouldn't
639     // happen since the thumbnail and main database versions should be in sync.
640     // We'll just continue without thumbnails & favicons in this case or any
641     // other error.
642     LOG(WARNING) << "Could not initialize the thumbnail database.";
643     thumbnail_db_.reset();
644   }
645
646   // Archived database.
647   if (db_->needs_version_17_migration()) {
648     // See needs_version_17_migration() decl for more. In this case, we want
649     // to delete the archived database and need to do so before we try to
650     // open the file. We can ignore any error (maybe the file doesn't exist).
651     sql::Connection::Delete(archived_name);
652   }
653   archived_db_.reset(new ArchivedDatabase());
654   if (!archived_db_->Init(archived_name)) {
655     LOG(WARNING) << "Could not initialize the archived database.";
656     archived_db_.reset();
657   }
658
659   // Generate the history and thumbnail database metrics only after performing
660   // any migration work.
661   if (base::RandInt(1, 100) == 50) {
662     // Only do this computation sometimes since it can be expensive.
663     db_->ComputeDatabaseMetrics(history_name);
664     if (thumbnail_db_)
665       thumbnail_db_->ComputeDatabaseMetrics();
666   }
667
668   // Tell the expiration module about all the nice databases we made. This must
669   // happen before db_->Init() is called since the callback ForceArchiveHistory
670   // may need to expire stuff.
671   //
672   // *sigh*, this can all be cleaned up when that migration code is removed.
673   // The main DB initialization should intuitively be first (not that it
674   // actually matters) and the expirer should be set last.
675   expirer_.SetDatabases(db_.get(), archived_db_.get(), thumbnail_db_.get());
676
677   // Open the long-running transaction.
678   db_->BeginTransaction();
679   if (thumbnail_db_)
680     thumbnail_db_->BeginTransaction();
681   if (archived_db_)
682     archived_db_->BeginTransaction();
683
684   // Get the first item in our database.
685   db_->GetStartDate(&first_recorded_time_);
686
687   // Start expiring old stuff.
688   expirer_.StartArchivingOldStuff(TimeDelta::FromDays(kArchiveDaysThreshold));
689
690 #if defined(OS_ANDROID)
691   if (thumbnail_db_) {
692     android_provider_backend_.reset(new AndroidProviderBackend(
693         GetAndroidCacheFileName(), db_.get(), thumbnail_db_.get(),
694         bookmark_service_, delegate_.get()));
695   }
696 #endif
697
698   HISTOGRAM_TIMES("History.InitTime",
699                   TimeTicks::Now() - beginning_time);
700 }
701
702 void HistoryBackend::OnMemoryPressure(
703     base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) {
704   bool trim_aggressively = memory_pressure_level ==
705       base::MemoryPressureListener::MEMORY_PRESSURE_CRITICAL;
706   if (db_)
707     db_->TrimMemory(trim_aggressively);
708   if (thumbnail_db_)
709     thumbnail_db_->TrimMemory(trim_aggressively);
710   if (archived_db_)
711     archived_db_->TrimMemory(trim_aggressively);
712 }
713
714 void HistoryBackend::CloseAllDatabases() {
715   if (db_) {
716     // Commit the long-running transaction.
717     db_->CommitTransaction();
718     db_.reset();
719     // Forget the first recorded time since the database is closed.
720     first_recorded_time_ = base::Time();
721   }
722   if (thumbnail_db_) {
723     thumbnail_db_->CommitTransaction();
724     thumbnail_db_.reset();
725   }
726   if (archived_db_) {
727     archived_db_->CommitTransaction();
728     archived_db_.reset();
729   }
730 }
731
732 std::pair<URLID, VisitID> HistoryBackend::AddPageVisit(
733     const GURL& url,
734     Time time,
735     VisitID referring_visit,
736     content::PageTransition transition,
737     VisitSource visit_source) {
738   // Top-level frame navigations are visible, everything else is hidden
739   bool new_hidden = !content::PageTransitionIsMainFrame(transition);
740
741   // NOTE: This code must stay in sync with
742   // ExpireHistoryBackend::ExpireURLsForVisits().
743   // TODO(pkasting): http://b/1148304 We shouldn't be marking so many URLs as
744   // typed, which would eliminate the need for this code.
745   int typed_increment = 0;
746   content::PageTransition transition_type =
747       content::PageTransitionStripQualifier(transition);
748   if ((transition_type == content::PAGE_TRANSITION_TYPED &&
749       !content::PageTransitionIsRedirect(transition)) ||
750       transition_type == content::PAGE_TRANSITION_KEYWORD_GENERATED)
751     typed_increment = 1;
752
753 #if defined(OS_ANDROID)
754   // Only count the page visit if it came from user browsing and only count it
755   // once when cycling through a redirect chain.
756   if (visit_source == SOURCE_BROWSED &&
757       (transition & content::PAGE_TRANSITION_CHAIN_END) != 0) {
758     RecordTopPageVisitStats(url);
759   }
760 #endif
761
762   // See if this URL is already in the DB.
763   URLRow url_info(url);
764   URLID url_id = db_->GetRowForURL(url, &url_info);
765   if (url_id) {
766     // Update of an existing row.
767     if (content::PageTransitionStripQualifier(transition) !=
768         content::PAGE_TRANSITION_RELOAD)
769       url_info.set_visit_count(url_info.visit_count() + 1);
770     if (typed_increment)
771       url_info.set_typed_count(url_info.typed_count() + typed_increment);
772     if (url_info.last_visit() < time)
773       url_info.set_last_visit(time);
774
775     // Only allow un-hiding of pages, never hiding.
776     if (!new_hidden)
777       url_info.set_hidden(false);
778
779     db_->UpdateURLRow(url_id, url_info);
780   } else {
781     // Addition of a new row.
782     url_info.set_visit_count(1);
783     url_info.set_typed_count(typed_increment);
784     url_info.set_last_visit(time);
785     url_info.set_hidden(new_hidden);
786
787     url_id = db_->AddURL(url_info);
788     if (!url_id) {
789       NOTREACHED() << "Adding URL failed.";
790       return std::make_pair(0, 0);
791     }
792     url_info.id_ = url_id;
793   }
794
795   // Add the visit with the time to the database.
796   VisitRow visit_info(url_id, time, referring_visit, transition, 0);
797   VisitID visit_id = db_->AddVisit(&visit_info, visit_source);
798   NotifyVisitObservers(visit_info);
799
800   if (visit_info.visit_time < first_recorded_time_)
801     first_recorded_time_ = visit_info.visit_time;
802
803   // Broadcast a notification of the visit.
804   if (visit_id) {
805     if (typed_url_syncable_service_.get())
806       typed_url_syncable_service_->OnUrlVisited(transition, &url_info);
807
808     URLVisitedDetails* details = new URLVisitedDetails;
809     details->transition = transition;
810     details->row = url_info;
811     // TODO(meelapshah) Disabled due to potential PageCycler regression.
812     // Re-enable this.
813     // GetMostRecentRedirectsTo(url, &details->redirects);
814     BroadcastNotifications(chrome::NOTIFICATION_HISTORY_URL_VISITED, details);
815   } else {
816     VLOG(0) << "Failed to build visit insert statement:  "
817             << "url_id = " << url_id;
818   }
819
820   return std::make_pair(url_id, visit_id);
821 }
822
823 void HistoryBackend::AddPagesWithDetails(const URLRows& urls,
824                                          VisitSource visit_source) {
825   if (!db_)
826     return;
827
828   scoped_ptr<URLsModifiedDetails> modified(new URLsModifiedDetails);
829   for (URLRows::const_iterator i = urls.begin(); i != urls.end(); ++i) {
830     DCHECK(!i->last_visit().is_null());
831
832     // We will add to either the archived database or the main one depending on
833     // the date of the added visit.
834     URLDatabase* url_database;
835     VisitDatabase* visit_database;
836     if (IsExpiredVisitTime(i->last_visit())) {
837       if (!archived_db_)
838         return;  // No archived database to save it to, just forget this.
839       url_database = archived_db_.get();
840       visit_database = archived_db_.get();
841     } else {
842       url_database = db_.get();
843       visit_database = db_.get();
844     }
845
846     URLRow existing_url;
847     URLID url_id = url_database->GetRowForURL(i->url(), &existing_url);
848     if (!url_id) {
849       // Add the page if it doesn't exist.
850       url_id = url_database->AddURL(*i);
851       if (!url_id) {
852         NOTREACHED() << "Could not add row to DB";
853         return;
854       }
855
856       if (i->typed_count() > 0) {
857         modified->changed_urls.push_back(*i);
858         modified->changed_urls.back().set_id(url_id);  // *i likely has |id_| 0.
859       }
860     }
861
862     // TODO(shess): I'm not sure this case needs to exist anymore.
863     if (page_collector_) {
864       page_collector_->AddPageData(i->url(), i->last_visit(),
865                                    i->title(), string16());
866     }
867
868     // Sync code manages the visits itself.
869     if (visit_source != SOURCE_SYNCED) {
870       // Make up a visit to correspond to the last visit to the page.
871       VisitRow visit_info(url_id, i->last_visit(), 0,
872                           content::PageTransitionFromInt(
873                               content::PAGE_TRANSITION_LINK |
874                               content::PAGE_TRANSITION_CHAIN_START |
875                               content::PAGE_TRANSITION_CHAIN_END), 0);
876       if (!visit_database->AddVisit(&visit_info, visit_source)) {
877         NOTREACHED() << "Adding visit failed.";
878         return;
879       }
880       NotifyVisitObservers(visit_info);
881
882       if (visit_info.visit_time < first_recorded_time_)
883         first_recorded_time_ = visit_info.visit_time;
884     }
885   }
886
887   if (typed_url_syncable_service_.get())
888     typed_url_syncable_service_->OnUrlsModified(&modified->changed_urls);
889
890   // Broadcast a notification for typed URLs that have been modified. This
891   // will be picked up by the in-memory URL database on the main thread.
892   //
893   // TODO(brettw) bug 1140015: Add an "add page" notification so the history
894   // views can keep in sync.
895   BroadcastNotifications(chrome::NOTIFICATION_HISTORY_URLS_MODIFIED,
896                          modified.release());
897
898   ScheduleCommit();
899 }
900
901 bool HistoryBackend::IsExpiredVisitTime(const base::Time& time) {
902   return time < expirer_.GetCurrentArchiveTime();
903 }
904
905 void HistoryBackend::SetPageTitle(const GURL& url, const string16& title) {
906   if (!db_)
907     return;
908
909   if (page_collector_)
910     page_collector_->AddPageTitle(url, title);
911
912   // Search for recent redirects which should get the same title. We make a
913   // dummy list containing the exact URL visited if there are no redirects so
914   // the processing below can be the same.
915   history::RedirectList dummy_list;
916   history::RedirectList* redirects;
917   RedirectCache::iterator iter = recent_redirects_.Get(url);
918   if (iter != recent_redirects_.end()) {
919     redirects = &iter->second;
920
921     // This redirect chain should have the destination URL as the last item.
922     DCHECK(!redirects->empty());
923     DCHECK(redirects->back() == url);
924   } else {
925     // No redirect chain stored, make up one containing the URL we want so we
926     // can use the same logic below.
927     dummy_list.push_back(url);
928     redirects = &dummy_list;
929   }
930
931   scoped_ptr<URLsModifiedDetails> details(new URLsModifiedDetails);
932   for (size_t i = 0; i < redirects->size(); i++) {
933     URLRow row;
934     URLID row_id = db_->GetRowForURL(redirects->at(i), &row);
935     if (row_id && row.title() != title) {
936       row.set_title(title);
937       db_->UpdateURLRow(row_id, row);
938       details->changed_urls.push_back(row);
939     }
940   }
941
942   // Broadcast notifications for any URLs that have changed. This will
943   // update the in-memory database and the InMemoryURLIndex.
944   if (!details->changed_urls.empty()) {
945     if (typed_url_syncable_service_.get())
946       typed_url_syncable_service_->OnUrlsModified(&details->changed_urls);
947     BroadcastNotifications(chrome::NOTIFICATION_HISTORY_URLS_MODIFIED,
948                            details.release());
949     ScheduleCommit();
950   }
951 }
952
953 void HistoryBackend::AddPageNoVisitForBookmark(const GURL& url,
954                                                const string16& title) {
955   if (!db_)
956     return;
957
958   URLRow url_info(url);
959   URLID url_id = db_->GetRowForURL(url, &url_info);
960   if (url_id) {
961     // URL is already known, nothing to do.
962     return;
963   }
964
965   if (!title.empty()) {
966     url_info.set_title(title);
967   } else {
968     url_info.set_title(UTF8ToUTF16(url.spec()));
969   }
970
971   url_info.set_last_visit(Time::Now());
972   // Mark the page hidden. If the user types it in, it'll unhide.
973   url_info.set_hidden(true);
974
975   db_->AddURL(url_info);
976 }
977
978 void HistoryBackend::IterateURLs(
979     const scoped_refptr<visitedlink::VisitedLinkDelegate::URLEnumerator>&
980     iterator) {
981   if (db_) {
982     HistoryDatabase::URLEnumerator e;
983     if (db_->InitURLEnumeratorForEverything(&e)) {
984       URLRow info;
985       while (e.GetNextURL(&info)) {
986         iterator->OnURL(info.url());
987       }
988       iterator->OnComplete(true);  // Success.
989       return;
990     }
991   }
992   iterator->OnComplete(false);  // Failure.
993 }
994
995 bool HistoryBackend::GetAllTypedURLs(URLRows* urls) {
996   if (db_)
997     return db_->GetAllTypedUrls(urls);
998   return false;
999 }
1000
1001 bool HistoryBackend::GetVisitsForURL(URLID id, VisitVector* visits) {
1002   if (db_)
1003     return db_->GetVisitsForURL(id, visits);
1004   return false;
1005 }
1006
1007 bool HistoryBackend::GetMostRecentVisitsForURL(URLID id,
1008                                                int max_visits,
1009                                                VisitVector* visits) {
1010   if (db_)
1011     return db_->GetMostRecentVisitsForURL(id, max_visits, visits);
1012   return false;
1013 }
1014
1015 bool HistoryBackend::UpdateURL(URLID id, const history::URLRow& url) {
1016   if (db_)
1017     return db_->UpdateURLRow(id, url);
1018   return false;
1019 }
1020
1021 bool HistoryBackend::AddVisits(const GURL& url,
1022                                const std::vector<VisitInfo>& visits,
1023                                VisitSource visit_source) {
1024   if (db_) {
1025     for (std::vector<VisitInfo>::const_iterator visit = visits.begin();
1026          visit != visits.end(); ++visit) {
1027       if (!AddPageVisit(
1028               url, visit->first, 0, visit->second, visit_source).first) {
1029         return false;
1030       }
1031     }
1032     ScheduleCommit();
1033     return true;
1034   }
1035   return false;
1036 }
1037
1038 bool HistoryBackend::RemoveVisits(const VisitVector& visits) {
1039   if (!db_)
1040     return false;
1041
1042   expirer_.ExpireVisits(visits);
1043   ScheduleCommit();
1044   return true;
1045 }
1046
1047 bool HistoryBackend::GetVisitsSource(const VisitVector& visits,
1048                                      VisitSourceMap* sources) {
1049   if (!db_)
1050     return false;
1051
1052   db_->GetVisitsSource(visits, sources);
1053   return true;
1054 }
1055
1056 bool HistoryBackend::GetURL(const GURL& url, history::URLRow* url_row) {
1057   if (db_)
1058     return db_->GetRowForURL(url, url_row) != 0;
1059   return false;
1060 }
1061
1062 void HistoryBackend::QueryURL(scoped_refptr<QueryURLRequest> request,
1063                               const GURL& url,
1064                               bool want_visits) {
1065   if (request->canceled())
1066     return;
1067
1068   bool success = false;
1069   URLRow* row = &request->value.a;
1070   VisitVector* visits = &request->value.b;
1071   if (db_) {
1072     if (db_->GetRowForURL(url, row)) {
1073       // Have a row.
1074       success = true;
1075
1076       // Optionally query the visits.
1077       if (want_visits)
1078         db_->GetVisitsForURL(row->id(), visits);
1079     }
1080   }
1081   request->ForwardResult(request->handle(), success, row, visits);
1082 }
1083
1084 TypedUrlSyncableService* HistoryBackend::GetTypedUrlSyncableService() const {
1085   return typed_url_syncable_service_.get();
1086 }
1087
1088 // Segment usage ---------------------------------------------------------------
1089
1090 void HistoryBackend::DeleteOldSegmentData() {
1091   if (db_)
1092     db_->DeleteSegmentData(Time::Now() -
1093                            TimeDelta::FromDays(kSegmentDataRetention));
1094 }
1095
1096 void HistoryBackend::QuerySegmentUsage(
1097     scoped_refptr<QuerySegmentUsageRequest> request,
1098     const Time from_time,
1099     int max_result_count) {
1100   if (request->canceled())
1101     return;
1102
1103   if (db_) {
1104     db_->QuerySegmentUsage(from_time, max_result_count, &request->value.get());
1105
1106     // If this is the first time we query segments, invoke
1107     // DeleteOldSegmentData asynchronously. We do this to cleanup old
1108     // entries.
1109     if (!segment_queried_) {
1110       segment_queried_ = true;
1111       base::MessageLoop::current()->PostTask(
1112           FROM_HERE,
1113           base::Bind(&HistoryBackend::DeleteOldSegmentData, this));
1114     }
1115   }
1116   request->ForwardResult(request->handle(), &request->value.get());
1117 }
1118
1119 void HistoryBackend::IncreaseSegmentDuration(const GURL& url,
1120                                              base::Time time,
1121                                              base::TimeDelta delta) {
1122   if (!db_)
1123     return;
1124
1125   const std::string segment_name(VisitSegmentDatabase::ComputeSegmentName(url));
1126   SegmentID segment_id = db_->GetSegmentNamed(segment_name);
1127   if (!segment_id) {
1128     URLID url_id = db_->GetRowForURL(url, NULL);
1129     if (!url_id)
1130       return;
1131     segment_id = db_->CreateSegment(url_id, segment_name);
1132     if (!segment_id)
1133       return;
1134   }
1135   SegmentDurationID duration_id;
1136   base::TimeDelta total_delta;
1137   if (!db_->GetSegmentDuration(segment_id, time, &duration_id,
1138                                &total_delta)) {
1139     db_->CreateSegmentDuration(segment_id, time, delta);
1140     return;
1141   }
1142   total_delta += delta;
1143   db_->SetSegmentDuration(duration_id, total_delta);
1144 }
1145
1146 void HistoryBackend::QuerySegmentDuration(
1147     scoped_refptr<QuerySegmentUsageRequest> request,
1148     const base::Time from_time,
1149     int max_result_count) {
1150   if (request->canceled())
1151     return;
1152
1153   if (db_) {
1154     db_->QuerySegmentDuration(from_time, max_result_count,
1155                               &request->value.get());
1156   }
1157   request->ForwardResult(request->handle(), &request->value.get());
1158 }
1159
1160 // Keyword visits --------------------------------------------------------------
1161
1162 void HistoryBackend::SetKeywordSearchTermsForURL(const GURL& url,
1163                                                  TemplateURLID keyword_id,
1164                                                  const string16& term) {
1165   if (!db_)
1166     return;
1167
1168   // Get the ID for this URL.
1169   URLID url_id = db_->GetRowForURL(url, NULL);
1170   if (!url_id) {
1171     // There is a small possibility the url was deleted before the keyword
1172     // was added. Ignore the request.
1173     return;
1174   }
1175
1176   db_->SetKeywordSearchTermsForURL(url_id, keyword_id, term);
1177
1178   BroadcastNotifications(
1179       chrome::NOTIFICATION_HISTORY_KEYWORD_SEARCH_TERM_UPDATED,
1180       new KeywordSearchUpdatedDetails(url, keyword_id, term));
1181   ScheduleCommit();
1182 }
1183
1184 void HistoryBackend::DeleteAllSearchTermsForKeyword(
1185     TemplateURLID keyword_id) {
1186   if (!db_)
1187     return;
1188
1189   db_->DeleteAllSearchTermsForKeyword(keyword_id);
1190   // TODO(sky): bug 1168470. Need to move from archive dbs too.
1191   ScheduleCommit();
1192 }
1193
1194 void HistoryBackend::GetMostRecentKeywordSearchTerms(
1195     scoped_refptr<GetMostRecentKeywordSearchTermsRequest> request,
1196     TemplateURLID keyword_id,
1197     const string16& prefix,
1198     int max_count) {
1199   if (request->canceled())
1200     return;
1201
1202   if (db_) {
1203     db_->GetMostRecentKeywordSearchTerms(keyword_id, prefix, max_count,
1204                                          &(request->value));
1205   }
1206   request->ForwardResult(request->handle(), &request->value);
1207 }
1208
1209 void HistoryBackend::DeleteKeywordSearchTermForURL(const GURL& url) {
1210   if (!db_)
1211     return;
1212
1213   URLID url_id = db_->GetRowForURL(url, NULL);
1214   if (!url_id)
1215     return;
1216   db_->DeleteKeywordSearchTermForURL(url_id);
1217
1218   BroadcastNotifications(
1219       chrome::NOTIFICATION_HISTORY_KEYWORD_SEARCH_TERM_DELETED,
1220       new KeywordSearchDeletedDetails(url));
1221   ScheduleCommit();
1222 }
1223
1224 // Downloads -------------------------------------------------------------------
1225
1226 void HistoryBackend::GetNextDownloadId(uint32* next_id) {
1227   if (db_)
1228     db_->GetNextDownloadId(next_id);
1229 }
1230
1231 // Get all the download entries from the database.
1232 void HistoryBackend::QueryDownloads(std::vector<DownloadRow>* rows) {
1233   if (db_)
1234     db_->QueryDownloads(rows);
1235 }
1236
1237 // Update a particular download entry.
1238 void HistoryBackend::UpdateDownload(const history::DownloadRow& data) {
1239   if (!db_)
1240     return;
1241   db_->UpdateDownload(data);
1242   ScheduleCommit();
1243 }
1244
1245 void HistoryBackend::CreateDownload(const history::DownloadRow& history_info,
1246                                     bool* success) {
1247   if (!db_)
1248     return;
1249   *success = db_->CreateDownload(history_info);
1250   ScheduleCommit();
1251 }
1252
1253 void HistoryBackend::RemoveDownloads(const std::set<uint32>& ids) {
1254   if (!db_)
1255     return;
1256   size_t downloads_count_before = db_->CountDownloads();
1257   base::TimeTicks started_removing = base::TimeTicks::Now();
1258   // HistoryBackend uses a long-running Transaction that is committed
1259   // periodically, so this loop doesn't actually hit the disk too hard.
1260   for (std::set<uint32>::const_iterator it = ids.begin();
1261        it != ids.end(); ++it) {
1262     db_->RemoveDownload(*it);
1263   }
1264   ScheduleCommit();
1265   base::TimeTicks finished_removing = base::TimeTicks::Now();
1266   size_t downloads_count_after = db_->CountDownloads();
1267
1268   DCHECK_LE(downloads_count_after, downloads_count_before);
1269   if (downloads_count_after > downloads_count_before)
1270     return;
1271   size_t num_downloads_deleted = downloads_count_before - downloads_count_after;
1272   UMA_HISTOGRAM_COUNTS("Download.DatabaseRemoveDownloadsCount",
1273                         num_downloads_deleted);
1274   base::TimeDelta micros = (1000 * (finished_removing - started_removing));
1275   UMA_HISTOGRAM_TIMES("Download.DatabaseRemoveDownloadsTime", micros);
1276   if (num_downloads_deleted > 0) {
1277     UMA_HISTOGRAM_TIMES("Download.DatabaseRemoveDownloadsTimePerRecord",
1278                         (1000 * micros) / num_downloads_deleted);
1279   }
1280   DCHECK_GE(ids.size(), num_downloads_deleted);
1281   if (ids.size() < num_downloads_deleted)
1282     return;
1283   UMA_HISTOGRAM_COUNTS("Download.DatabaseRemoveDownloadsCountNotRemoved",
1284                         ids.size() - num_downloads_deleted);
1285 }
1286
1287 void HistoryBackend::QueryHistory(scoped_refptr<QueryHistoryRequest> request,
1288                                   const string16& text_query,
1289                                   const QueryOptions& options) {
1290   if (request->canceled())
1291     return;
1292
1293   TimeTicks beginning_time = TimeTicks::Now();
1294
1295   if (db_) {
1296     if (text_query.empty()) {
1297       // Basic history query for the main database.
1298       QueryHistoryBasic(db_.get(), db_.get(), options, &request->value);
1299
1300       // Now query the archived database. This is a bit tricky because we don't
1301       // want to query it if the queried time range isn't going to find anything
1302       // in it.
1303       // TODO(brettw) bug 1171036: do blimpie querying for the archived database
1304       // as well.
1305       // if (archived_db_.get() &&
1306       //     expirer_.GetCurrentArchiveTime() - TimeDelta::FromDays(7)) {
1307     } else {
1308       // Text history query.
1309       QueryHistoryText(db_.get(), db_.get(), text_query, options,
1310                        &request->value);
1311       if (archived_db_.get() &&
1312           expirer_.GetCurrentArchiveTime() >= options.begin_time) {
1313         QueryHistoryText(archived_db_.get(), archived_db_.get(), text_query,
1314                          options, &request->value);
1315       }
1316     }
1317   }
1318
1319   request->ForwardResult(request->handle(), &request->value);
1320
1321   UMA_HISTOGRAM_TIMES("History.QueryHistory",
1322                       TimeTicks::Now() - beginning_time);
1323 }
1324
1325 // Basic time-based querying of history.
1326 void HistoryBackend::QueryHistoryBasic(URLDatabase* url_db,
1327                                        VisitDatabase* visit_db,
1328                                        const QueryOptions& options,
1329                                        QueryResults* result) {
1330   // First get all visits.
1331   VisitVector visits;
1332   bool has_more_results = visit_db->GetVisibleVisitsInRange(options, &visits);
1333   DCHECK(static_cast<int>(visits.size()) <= options.EffectiveMaxCount());
1334
1335   // Now add them and the URL rows to the results.
1336   URLResult url_result;
1337   for (size_t i = 0; i < visits.size(); i++) {
1338     const VisitRow visit = visits[i];
1339
1340     // Add a result row for this visit, get the URL info from the DB.
1341     if (!url_db->GetURLRow(visit.url_id, &url_result)) {
1342       VLOG(0) << "Failed to get id " << visit.url_id
1343               << " from history.urls.";
1344       continue;  // DB out of sync and URL doesn't exist, try to recover.
1345     }
1346
1347     if (!url_result.url().is_valid()) {
1348       VLOG(0) << "Got invalid URL from history.urls with id "
1349               << visit.url_id << ":  "
1350               << url_result.url().possibly_invalid_spec();
1351       continue;  // Don't report invalid URLs in case of corruption.
1352     }
1353
1354     // The archived database may be out of sync with respect to starring,
1355     // titles, last visit date, etc. Therefore, we query the main DB if the
1356     // current URL database is not the main one.
1357     if (url_db == db_.get()) {
1358       // Currently querying the archived DB, update with the main database to
1359       // catch any interesting stuff. This will update it if it exists in the
1360       // main DB, and do nothing otherwise.
1361       db_->GetRowForURL(url_result.url(), &url_result);
1362     }
1363
1364     url_result.set_visit_time(visit.visit_time);
1365
1366     // Set whether the visit was blocked for a managed user by looking at the
1367     // transition type.
1368     url_result.set_blocked_visit(
1369         (visit.transition & content::PAGE_TRANSITION_BLOCKED) != 0);
1370
1371     // We don't set any of the query-specific parts of the URLResult, since
1372     // snippets and stuff don't apply to basic querying.
1373     result->AppendURLBySwapping(&url_result);
1374   }
1375
1376   if (!has_more_results && options.begin_time <= first_recorded_time_)
1377     result->set_reached_beginning(true);
1378 }
1379
1380 // Text-based querying of history.
1381 void HistoryBackend::QueryHistoryText(URLDatabase* url_db,
1382                                       VisitDatabase* visit_db,
1383                                       const string16& text_query,
1384                                       const QueryOptions& options,
1385                                       QueryResults* result) {
1386   URLRows text_matches;
1387   url_db->GetTextMatches(text_query, &text_matches);
1388
1389   std::vector<URLResult> matching_visits;
1390   VisitVector visits;    // Declare outside loop to prevent re-construction.
1391   for (size_t i = 0; i < text_matches.size(); i++) {
1392     const URLRow& text_match = text_matches[i];
1393     // Get all visits for given URL match.
1394     visit_db->GetVisibleVisitsForURL(text_match.id(), options, &visits);
1395     for (size_t j = 0; j < visits.size(); j++) {
1396       URLResult url_result(text_match);
1397       url_result.set_visit_time(visits[j].visit_time);
1398       matching_visits.push_back(url_result);
1399     }
1400   }
1401
1402   std::sort(matching_visits.begin(), matching_visits.end(),
1403             URLResult::CompareVisitTime);
1404
1405   size_t max_results = options.max_count == 0 ?
1406       std::numeric_limits<size_t>::max() : static_cast<int>(options.max_count);
1407   for (std::vector<URLResult>::iterator it = matching_visits.begin();
1408        it != matching_visits.end() && result->size() < max_results; ++it) {
1409     result->AppendURLBySwapping(&(*it));
1410   }
1411
1412   if (matching_visits.size() == result->size() &&
1413       options.begin_time <= first_recorded_time_)
1414     result->set_reached_beginning(true);
1415 }
1416
1417 // Frontend to GetMostRecentRedirectsFrom from the history thread.
1418 void HistoryBackend::QueryRedirectsFrom(
1419     scoped_refptr<QueryRedirectsRequest> request,
1420     const GURL& url) {
1421   if (request->canceled())
1422     return;
1423   bool success = GetMostRecentRedirectsFrom(url, &request->value);
1424   request->ForwardResult(request->handle(), url, success, &request->value);
1425 }
1426
1427 void HistoryBackend::QueryRedirectsTo(
1428     scoped_refptr<QueryRedirectsRequest> request,
1429     const GURL& url) {
1430   if (request->canceled())
1431     return;
1432   bool success = GetMostRecentRedirectsTo(url, &request->value);
1433   request->ForwardResult(request->handle(), url, success, &request->value);
1434 }
1435
1436 void HistoryBackend::GetVisibleVisitCountToHost(
1437     scoped_refptr<GetVisibleVisitCountToHostRequest> request,
1438     const GURL& url) {
1439   if (request->canceled())
1440     return;
1441   int count = 0;
1442   Time first_visit;
1443   const bool success = db_.get() &&
1444       db_->GetVisibleVisitCountToHost(url, &count, &first_visit);
1445   request->ForwardResult(request->handle(), success, count, first_visit);
1446 }
1447
1448 void HistoryBackend::QueryTopURLsAndRedirects(
1449     scoped_refptr<QueryTopURLsAndRedirectsRequest> request,
1450     int result_count) {
1451   if (request->canceled())
1452     return;
1453
1454   if (!db_) {
1455     request->ForwardResult(request->handle(), false, NULL, NULL);
1456     return;
1457   }
1458
1459   std::vector<GURL>* top_urls = &request->value.a;
1460   history::RedirectMap* redirects = &request->value.b;
1461
1462   ScopedVector<PageUsageData> data;
1463   db_->QuerySegmentUsage(base::Time::Now() - base::TimeDelta::FromDays(90),
1464       result_count, &data.get());
1465
1466   for (size_t i = 0; i < data.size(); ++i) {
1467     top_urls->push_back(data[i]->GetURL());
1468     RefCountedVector<GURL>* list = new RefCountedVector<GURL>;
1469     GetMostRecentRedirectsFrom(top_urls->back(), &list->data);
1470     (*redirects)[top_urls->back()] = list;
1471   }
1472
1473   request->ForwardResult(request->handle(), true, top_urls, redirects);
1474 }
1475
1476 // Will replace QueryTopURLsAndRedirectsRequest.
1477 void HistoryBackend::QueryMostVisitedURLs(
1478     scoped_refptr<QueryMostVisitedURLsRequest> request,
1479     int result_count,
1480     int days_back) {
1481   if (request->canceled())
1482     return;
1483
1484   if (!db_) {
1485     // No History Database - return an empty list.
1486     request->ForwardResult(request->handle(), MostVisitedURLList());
1487     return;
1488   }
1489
1490   MostVisitedURLList* result = &request->value;
1491   QueryMostVisitedURLsImpl(result_count, days_back, result);
1492   request->ForwardResult(request->handle(), *result);
1493 }
1494
1495 void HistoryBackend::QueryFilteredURLs(
1496       scoped_refptr<QueryFilteredURLsRequest> request,
1497       int result_count,
1498       const history::VisitFilter& filter,
1499       bool extended_info)  {
1500   if (request->canceled())
1501     return;
1502
1503   base::Time request_start = base::Time::Now();
1504
1505   if (!db_) {
1506     // No History Database - return an empty list.
1507     request->ForwardResult(request->handle(), FilteredURLList());
1508     return;
1509   }
1510
1511   VisitVector visits;
1512   db_->GetDirectVisitsDuringTimes(filter, 0, &visits);
1513
1514   std::map<URLID, double> score_map;
1515   for (size_t i = 0; i < visits.size(); ++i) {
1516     score_map[visits[i].url_id] += filter.GetVisitScore(visits[i]);
1517   }
1518
1519   // TODO(georgey): experiment with visit_segment database granularity (it is
1520   // currently 24 hours) to use it directly instead of using visits database,
1521   // which is considerably slower.
1522   ScopedVector<PageUsageData> data;
1523   data.reserve(score_map.size());
1524   for (std::map<URLID, double>::iterator it = score_map.begin();
1525        it != score_map.end(); ++it) {
1526     PageUsageData* pud = new PageUsageData(it->first);
1527     pud->SetScore(it->second);
1528     data.push_back(pud);
1529   }
1530
1531   // Limit to the top |result_count| results.
1532   std::sort(data.begin(), data.end(), PageUsageData::Predicate);
1533   if (result_count && implicit_cast<int>(data.size()) > result_count)
1534     data.resize(result_count);
1535
1536   for (size_t i = 0; i < data.size(); ++i) {
1537     URLRow info;
1538     if (db_->GetURLRow(data[i]->GetID(), &info)) {
1539       data[i]->SetURL(info.url());
1540       data[i]->SetTitle(info.title());
1541     }
1542   }
1543
1544   FilteredURLList& result = request->value;
1545   for (size_t i = 0; i < data.size(); ++i) {
1546     PageUsageData* current_data = data[i];
1547     FilteredURL url(*current_data);
1548
1549     if (extended_info) {
1550       VisitVector visits;
1551       db_->GetVisitsForURL(current_data->GetID(), &visits);
1552       if (visits.size() > 0) {
1553         url.extended_info.total_visits = visits.size();
1554         for (size_t i = 0; i < visits.size(); ++i) {
1555           url.extended_info.duration_opened +=
1556               visits[i].visit_duration.InSeconds();
1557           if (visits[i].visit_time > url.extended_info.last_visit_time) {
1558             url.extended_info.last_visit_time = visits[i].visit_time;
1559           }
1560         }
1561         // TODO(macourteau): implement the url.extended_info.visits stat.
1562       }
1563     }
1564     result.push_back(url);
1565   }
1566
1567   int delta_time = std::max(1, std::min(999,
1568       static_cast<int>((base::Time::Now() - request_start).InMilliseconds())));
1569   STATIC_HISTOGRAM_POINTER_BLOCK(
1570       "NewTabPage.SuggestedSitesLoadTime",
1571       Add(delta_time),
1572       base::LinearHistogram::FactoryGet("NewTabPage.SuggestedSitesLoadTime",
1573           1, 1000, 100, base::Histogram::kUmaTargetedHistogramFlag));
1574
1575   request->ForwardResult(request->handle(), result);
1576 }
1577
1578 void HistoryBackend::QueryMostVisitedURLsImpl(int result_count,
1579                                               int days_back,
1580                                               MostVisitedURLList* result) {
1581   if (!db_)
1582     return;
1583
1584   ScopedVector<PageUsageData> data;
1585   db_->QuerySegmentUsage(base::Time::Now() -
1586                          base::TimeDelta::FromDays(days_back),
1587                          result_count, &data.get());
1588
1589   for (size_t i = 0; i < data.size(); ++i) {
1590     PageUsageData* current_data = data[i];
1591     RedirectList redirects;
1592     GetMostRecentRedirectsFrom(current_data->GetURL(), &redirects);
1593     MostVisitedURL url = MakeMostVisitedURL(*current_data, redirects);
1594     result->push_back(url);
1595   }
1596 }
1597
1598 void HistoryBackend::GetRedirectsFromSpecificVisit(
1599     VisitID cur_visit, history::RedirectList* redirects) {
1600   // Follow any redirects from the given visit and add them to the list.
1601   // It *should* be impossible to get a circular chain here, but we check
1602   // just in case to avoid infinite loops.
1603   GURL cur_url;
1604   std::set<VisitID> visit_set;
1605   visit_set.insert(cur_visit);
1606   while (db_->GetRedirectFromVisit(cur_visit, &cur_visit, &cur_url)) {
1607     if (visit_set.find(cur_visit) != visit_set.end()) {
1608       NOTREACHED() << "Loop in visit chain, giving up";
1609       return;
1610     }
1611     visit_set.insert(cur_visit);
1612     redirects->push_back(cur_url);
1613   }
1614 }
1615
1616 void HistoryBackend::GetRedirectsToSpecificVisit(
1617     VisitID cur_visit,
1618     history::RedirectList* redirects) {
1619   // Follow redirects going to cur_visit. These are added to |redirects| in
1620   // the order they are found. If a redirect chain looks like A -> B -> C and
1621   // |cur_visit| = C, redirects will be {B, A} in that order.
1622   if (!db_)
1623     return;
1624
1625   GURL cur_url;
1626   std::set<VisitID> visit_set;
1627   visit_set.insert(cur_visit);
1628   while (db_->GetRedirectToVisit(cur_visit, &cur_visit, &cur_url)) {
1629     if (visit_set.find(cur_visit) != visit_set.end()) {
1630       NOTREACHED() << "Loop in visit chain, giving up";
1631       return;
1632     }
1633     visit_set.insert(cur_visit);
1634     redirects->push_back(cur_url);
1635   }
1636 }
1637
1638 bool HistoryBackend::GetMostRecentRedirectsFrom(
1639     const GURL& from_url,
1640     history::RedirectList* redirects) {
1641   redirects->clear();
1642   if (!db_)
1643     return false;
1644
1645   URLID from_url_id = db_->GetRowForURL(from_url, NULL);
1646   VisitID cur_visit = db_->GetMostRecentVisitForURL(from_url_id, NULL);
1647   if (!cur_visit)
1648     return false;  // No visits for URL.
1649
1650   GetRedirectsFromSpecificVisit(cur_visit, redirects);
1651   return true;
1652 }
1653
1654 bool HistoryBackend::GetMostRecentRedirectsTo(
1655     const GURL& to_url,
1656     history::RedirectList* redirects) {
1657   redirects->clear();
1658   if (!db_)
1659     return false;
1660
1661   URLID to_url_id = db_->GetRowForURL(to_url, NULL);
1662   VisitID cur_visit = db_->GetMostRecentVisitForURL(to_url_id, NULL);
1663   if (!cur_visit)
1664     return false;  // No visits for URL.
1665
1666   GetRedirectsToSpecificVisit(cur_visit, redirects);
1667   return true;
1668 }
1669
1670 void HistoryBackend::ScheduleAutocomplete(HistoryURLProvider* provider,
1671                                           HistoryURLProviderParams* params) {
1672   // ExecuteWithDB should handle the NULL database case.
1673   provider->ExecuteWithDB(this, db_.get(), params);
1674 }
1675
1676 void HistoryBackend::DeleteFTSIndexDatabases() {
1677   // Find files on disk matching the text databases file pattern so we can
1678   // quickly test for and delete them.
1679   base::FilePath::StringType filepattern =
1680       FILE_PATH_LITERAL("History Index *");
1681   base::FileEnumerator enumerator(
1682       history_dir_, false, base::FileEnumerator::FILES, filepattern);
1683   int num_databases_deleted = 0;
1684   base::FilePath current_file;
1685   while (!(current_file = enumerator.Next()).empty()) {
1686     if (sql::Connection::Delete(current_file))
1687       num_databases_deleted++;
1688   }
1689   UMA_HISTOGRAM_COUNTS("History.DeleteFTSIndexDatabases",
1690                        num_databases_deleted);
1691 }
1692
1693 void HistoryBackend::SetPageContents(const GURL& url,
1694                                      const string16& contents) {
1695   if (page_collector_)
1696     page_collector_->AddPageContents(url, contents);
1697 }
1698
1699 void HistoryBackend::GetFavicons(
1700     const std::vector<GURL>& icon_urls,
1701     int icon_types,
1702     int desired_size_in_dip,
1703     const std::vector<ui::ScaleFactor>& desired_scale_factors,
1704     std::vector<chrome::FaviconBitmapResult>* bitmap_results) {
1705   UpdateFaviconMappingsAndFetchImpl(NULL, icon_urls, icon_types,
1706                                     desired_size_in_dip, desired_scale_factors,
1707                                     bitmap_results);
1708 }
1709
1710 void HistoryBackend::GetLargestFaviconForURL(
1711       const GURL& page_url,
1712       const std::vector<int>& icon_types,
1713       int minimum_size_in_pixels,
1714       chrome::FaviconBitmapResult* favicon_bitmap_result) {
1715   DCHECK(favicon_bitmap_result);
1716
1717   if (!db_ || !thumbnail_db_)
1718     return;
1719
1720   TimeTicks beginning_time = TimeTicks::Now();
1721
1722   std::vector<IconMapping> icon_mappings;
1723   if (!thumbnail_db_->GetIconMappingsForPageURL(page_url, &icon_mappings) ||
1724       icon_mappings.empty())
1725     return;
1726
1727   int required_icon_types = 0;
1728   for (std::vector<int>::const_iterator i = icon_types.begin();
1729        i != icon_types.end(); ++i) {
1730     required_icon_types |= *i;
1731   }
1732
1733   // Find the largest bitmap for each IconType placing in
1734   // |largest_favicon_bitmaps|.
1735   std::map<chrome::IconType, FaviconBitmap> largest_favicon_bitmaps;
1736   for (std::vector<IconMapping>::const_iterator i = icon_mappings.begin();
1737        i != icon_mappings.end(); ++i) {
1738     if (!(i->icon_type & required_icon_types))
1739       continue;
1740     std::vector<FaviconBitmapIDSize> bitmap_id_sizes;
1741     thumbnail_db_->GetFaviconBitmapIDSizes(i->icon_id, &bitmap_id_sizes);
1742     FaviconBitmap& largest = largest_favicon_bitmaps[i->icon_type];
1743     for (std::vector<FaviconBitmapIDSize>::const_iterator j =
1744              bitmap_id_sizes.begin(); j != bitmap_id_sizes.end(); ++j) {
1745       if (largest.bitmap_id == 0 ||
1746           (largest.pixel_size.width() < j->pixel_size.width() &&
1747            largest.pixel_size.height() < j->pixel_size.height())) {
1748         largest.icon_id = i->icon_id;
1749         largest.bitmap_id = j->bitmap_id;
1750         largest.pixel_size = j->pixel_size;
1751       }
1752     }
1753   }
1754   if (largest_favicon_bitmaps.empty())
1755     return;
1756
1757   // Find an icon which is larger than minimum_size_in_pixels in the order of
1758   // icon_types.
1759   FaviconBitmap largest_icon;
1760   for (std::vector<int>::const_iterator t = icon_types.begin();
1761        t != icon_types.end(); ++t) {
1762     for (std::map<chrome::IconType, FaviconBitmap>::const_iterator f =
1763             largest_favicon_bitmaps.begin(); f != largest_favicon_bitmaps.end();
1764         ++f) {
1765       if (f->first & *t &&
1766           (largest_icon.bitmap_id == 0 ||
1767            (largest_icon.pixel_size.height() < f->second.pixel_size.height() &&
1768             largest_icon.pixel_size.width() < f->second.pixel_size.width()))) {
1769         largest_icon = f->second;
1770       }
1771     }
1772     if (largest_icon.pixel_size.width() > minimum_size_in_pixels &&
1773         largest_icon.pixel_size.height() > minimum_size_in_pixels)
1774       break;
1775   }
1776
1777   GURL icon_url;
1778   chrome::IconType icon_type;
1779   if (!thumbnail_db_->GetFaviconHeader(largest_icon.icon_id, &icon_url,
1780                                        &icon_type)) {
1781     return;
1782   }
1783
1784   base::Time last_updated;
1785   chrome::FaviconBitmapResult bitmap_result;
1786   bitmap_result.icon_url = icon_url;
1787   bitmap_result.icon_type = icon_type;
1788   if (!thumbnail_db_->GetFaviconBitmap(largest_icon.bitmap_id,
1789                                        &last_updated,
1790                                        &bitmap_result.bitmap_data,
1791                                        &bitmap_result.pixel_size)) {
1792     return;
1793   }
1794
1795   bitmap_result.expired = (Time::Now() - last_updated) >
1796       TimeDelta::FromDays(kFaviconRefetchDays);
1797   if (bitmap_result.is_valid())
1798     *favicon_bitmap_result = bitmap_result;
1799
1800   HISTOGRAM_TIMES("History.GetLargestFaviconForURL",
1801                   TimeTicks::Now() - beginning_time);
1802 }
1803
1804 void HistoryBackend::GetFaviconsForURL(
1805     const GURL& page_url,
1806     int icon_types,
1807     int desired_size_in_dip,
1808     const std::vector<ui::ScaleFactor>& desired_scale_factors,
1809     std::vector<chrome::FaviconBitmapResult>* bitmap_results) {
1810   DCHECK(bitmap_results);
1811   GetFaviconsFromDB(page_url, icon_types, desired_size_in_dip,
1812                     desired_scale_factors, bitmap_results);
1813 }
1814
1815 void HistoryBackend::GetFaviconForID(
1816     chrome::FaviconID favicon_id,
1817     int desired_size_in_dip,
1818     ui::ScaleFactor desired_scale_factor,
1819     std::vector<chrome::FaviconBitmapResult>* bitmap_results) {
1820   std::vector<chrome::FaviconID> favicon_ids;
1821   favicon_ids.push_back(favicon_id);
1822   std::vector<ui::ScaleFactor> desired_scale_factors;
1823   desired_scale_factors.push_back(desired_scale_factor);
1824
1825   // Get results from DB.
1826   GetFaviconBitmapResultsForBestMatch(favicon_ids,
1827                                       desired_size_in_dip,
1828                                       desired_scale_factors,
1829                                       bitmap_results);
1830 }
1831
1832 void HistoryBackend::UpdateFaviconMappingsAndFetch(
1833     const GURL& page_url,
1834     const std::vector<GURL>& icon_urls,
1835     int icon_types,
1836     int desired_size_in_dip,
1837     const std::vector<ui::ScaleFactor>& desired_scale_factors,
1838     std::vector<chrome::FaviconBitmapResult>* bitmap_results) {
1839   UpdateFaviconMappingsAndFetchImpl(&page_url, icon_urls, icon_types,
1840                                     desired_size_in_dip, desired_scale_factors,
1841                                     bitmap_results);
1842 }
1843
1844 void HistoryBackend::MergeFavicon(
1845     const GURL& page_url,
1846     const GURL& icon_url,
1847     chrome::IconType icon_type,
1848     scoped_refptr<base::RefCountedMemory> bitmap_data,
1849     const gfx::Size& pixel_size) {
1850   if (!thumbnail_db_ || !db_)
1851     return;
1852
1853   chrome::FaviconID favicon_id =
1854       thumbnail_db_->GetFaviconIDForFaviconURL(icon_url, icon_type, NULL);
1855
1856   if (!favicon_id) {
1857     // There is no favicon at |icon_url|, create it.
1858     favicon_id = thumbnail_db_->AddFavicon(icon_url, icon_type);
1859   }
1860
1861   std::vector<FaviconBitmapIDSize> bitmap_id_sizes;
1862   thumbnail_db_->GetFaviconBitmapIDSizes(favicon_id, &bitmap_id_sizes);
1863
1864   // If there is already a favicon bitmap of |pixel_size| at |icon_url|,
1865   // replace it.
1866   bool bitmap_identical = false;
1867   bool replaced_bitmap = false;
1868   for (size_t i = 0; i < bitmap_id_sizes.size(); ++i) {
1869     if (bitmap_id_sizes[i].pixel_size == pixel_size) {
1870       if (IsFaviconBitmapDataEqual(bitmap_id_sizes[i].bitmap_id, bitmap_data)) {
1871         thumbnail_db_->SetFaviconBitmapLastUpdateTime(
1872             bitmap_id_sizes[i].bitmap_id, base::Time::Now());
1873         bitmap_identical = true;
1874       } else {
1875         thumbnail_db_->SetFaviconBitmap(bitmap_id_sizes[i].bitmap_id,
1876             bitmap_data, base::Time::Now());
1877         replaced_bitmap = true;
1878       }
1879       break;
1880     }
1881   }
1882
1883   // Create a vector of the pixel sizes of the favicon bitmaps currently at
1884   // |icon_url|.
1885   std::vector<gfx::Size> favicon_sizes;
1886   for (size_t i = 0; i < bitmap_id_sizes.size(); ++i)
1887     favicon_sizes.push_back(bitmap_id_sizes[i].pixel_size);
1888
1889   if (!replaced_bitmap && !bitmap_identical) {
1890     // Set the preexisting favicon bitmaps as expired as the preexisting favicon
1891     // bitmaps are not consistent with the merged in data.
1892     thumbnail_db_->SetFaviconOutOfDate(favicon_id);
1893
1894     // Delete an arbitrary favicon bitmap to avoid going over the limit of
1895     // |kMaxFaviconBitmapsPerIconURL|.
1896     if (bitmap_id_sizes.size() >= kMaxFaviconBitmapsPerIconURL) {
1897       thumbnail_db_->DeleteFaviconBitmap(bitmap_id_sizes[0].bitmap_id);
1898       favicon_sizes.erase(favicon_sizes.begin());
1899     }
1900     thumbnail_db_->AddFaviconBitmap(favicon_id, bitmap_data, base::Time::Now(),
1901                                     pixel_size);
1902     favicon_sizes.push_back(pixel_size);
1903   }
1904
1905   // A site may have changed the favicons that it uses for |page_url|.
1906   // Example Scenario:
1907   //   page_url = news.google.com
1908   //   Initial State: www.google.com/favicon.ico 16x16, 32x32
1909   //   MergeFavicon(news.google.com, news.google.com/news_specific.ico, ...,
1910   //                ..., 16x16)
1911   //
1912   // Difficulties:
1913   // 1. Sync requires that a call to GetFaviconsForURL() returns the
1914   //    |bitmap_data| passed into MergeFavicon().
1915   //    - It is invalid for the 16x16 bitmap for www.google.com/favicon.ico to
1916   //      stay mapped to news.google.com because it would be unclear which 16x16
1917   //      bitmap should be returned via GetFaviconsForURL().
1918   //
1919   // 2. www.google.com/favicon.ico may be mapped to more than just
1920   //    news.google.com (eg www.google.com).
1921   //    - The 16x16 bitmap cannot be deleted from www.google.com/favicon.ico
1922   //
1923   // To resolve these problems, we copy all of the favicon bitmaps previously
1924   // mapped to news.google.com (|page_url|) and add them to the favicon at
1925   // news.google.com/news_specific.ico (|icon_url|). The favicon sizes for
1926   // |icon_url| are set to default to indicate that |icon_url| has incomplete
1927   // / incorrect data.
1928   // Difficulty 1: All but news.google.com/news_specific.ico are unmapped from
1929   //              news.google.com
1930   // Difficulty 2: The favicon bitmaps for www.google.com/favicon.ico are not
1931   //               modified.
1932
1933   std::vector<IconMapping> icon_mappings;
1934   thumbnail_db_->GetIconMappingsForPageURL(page_url, icon_type, &icon_mappings);
1935
1936   // Copy the favicon bitmaps mapped to |page_url| to the favicon at |icon_url|
1937   // till the limit of |kMaxFaviconBitmapsPerIconURL| is reached.
1938   for (size_t i = 0; i < icon_mappings.size(); ++i) {
1939     if (favicon_sizes.size() >= kMaxFaviconBitmapsPerIconURL)
1940       break;
1941
1942     if (icon_mappings[i].icon_url == icon_url)
1943       continue;
1944
1945     std::vector<FaviconBitmap> bitmaps_to_copy;
1946     thumbnail_db_->GetFaviconBitmaps(icon_mappings[i].icon_id,
1947                                      &bitmaps_to_copy);
1948     for (size_t j = 0; j < bitmaps_to_copy.size(); ++j) {
1949       // Do not add a favicon bitmap at a pixel size for which there is already
1950       // a favicon bitmap mapped to |icon_url|. The one there is more correct
1951       // and having multiple equally sized favicon bitmaps for |page_url| is
1952       // ambiguous in terms of GetFaviconsForURL().
1953       std::vector<gfx::Size>::iterator it = std::find(favicon_sizes.begin(),
1954           favicon_sizes.end(), bitmaps_to_copy[j].pixel_size);
1955       if (it != favicon_sizes.end())
1956         continue;
1957
1958       // Add the favicon bitmap as expired as it is not consistent with the
1959       // merged in data.
1960       thumbnail_db_->AddFaviconBitmap(favicon_id,
1961           bitmaps_to_copy[j].bitmap_data, base::Time(),
1962           bitmaps_to_copy[j].pixel_size);
1963       favicon_sizes.push_back(bitmaps_to_copy[j].pixel_size);
1964
1965       if (favicon_sizes.size() >= kMaxFaviconBitmapsPerIconURL)
1966         break;
1967     }
1968   }
1969
1970   // Update the favicon mappings such that only |icon_url| is mapped to
1971   // |page_url|.
1972   bool mapping_changed = false;
1973   if (icon_mappings.size() != 1 || icon_mappings[0].icon_url != icon_url) {
1974     std::vector<chrome::FaviconID> favicon_ids;
1975     favicon_ids.push_back(favicon_id);
1976     SetFaviconMappingsForPageAndRedirects(page_url, icon_type, favicon_ids);
1977     mapping_changed = true;
1978   }
1979
1980   if (mapping_changed || !bitmap_identical)
1981     SendFaviconChangedNotificationForPageAndRedirects(page_url);
1982   ScheduleCommit();
1983 }
1984
1985 void HistoryBackend::SetFavicons(
1986     const GURL& page_url,
1987     chrome::IconType icon_type,
1988     const std::vector<chrome::FaviconBitmapData>& favicon_bitmap_data) {
1989   if (!thumbnail_db_ || !db_)
1990     return;
1991
1992   DCHECK(ValidateSetFaviconsParams(favicon_bitmap_data));
1993
1994   // Build map of FaviconBitmapData for each icon url.
1995   typedef std::map<GURL, std::vector<chrome::FaviconBitmapData> >
1996       BitmapDataByIconURL;
1997   BitmapDataByIconURL grouped_by_icon_url;
1998   for (size_t i = 0; i < favicon_bitmap_data.size(); ++i) {
1999     const GURL& icon_url = favicon_bitmap_data[i].icon_url;
2000     grouped_by_icon_url[icon_url].push_back(favicon_bitmap_data[i]);
2001   }
2002
2003   // Track whether the method modifies or creates any favicon bitmaps, favicons
2004   // or icon mappings.
2005   bool data_modified = false;
2006
2007   std::vector<chrome::FaviconID> icon_ids;
2008   for (BitmapDataByIconURL::const_iterator it = grouped_by_icon_url.begin();
2009        it != grouped_by_icon_url.end(); ++it) {
2010     const GURL& icon_url = it->first;
2011     chrome::FaviconID icon_id =
2012         thumbnail_db_->GetFaviconIDForFaviconURL(icon_url, icon_type, NULL);
2013
2014     if (!icon_id) {
2015       // TODO(pkotwicz): Remove the favicon sizes attribute from
2016       // ThumbnailDatabase::AddFavicon().
2017       icon_id = thumbnail_db_->AddFavicon(icon_url, icon_type);
2018       data_modified = true;
2019     }
2020     icon_ids.push_back(icon_id);
2021
2022     if (!data_modified)
2023       SetFaviconBitmaps(icon_id, it->second, &data_modified);
2024     else
2025       SetFaviconBitmaps(icon_id, it->second, NULL);
2026   }
2027
2028   data_modified |=
2029     SetFaviconMappingsForPageAndRedirects(page_url, icon_type, icon_ids);
2030
2031   if (data_modified) {
2032     // Send notification to the UI as an icon mapping, favicon, or favicon
2033     // bitmap was changed by this function.
2034     SendFaviconChangedNotificationForPageAndRedirects(page_url);
2035   }
2036   ScheduleCommit();
2037 }
2038
2039 void HistoryBackend::SetFaviconsOutOfDateForPage(const GURL& page_url) {
2040   std::vector<IconMapping> icon_mappings;
2041
2042   if (!thumbnail_db_ ||
2043       !thumbnail_db_->GetIconMappingsForPageURL(page_url,
2044                                                 &icon_mappings))
2045     return;
2046
2047   for (std::vector<IconMapping>::iterator m = icon_mappings.begin();
2048        m != icon_mappings.end(); ++m) {
2049     thumbnail_db_->SetFaviconOutOfDate(m->icon_id);
2050   }
2051   ScheduleCommit();
2052 }
2053
2054 void HistoryBackend::CloneFavicons(const GURL& old_page_url,
2055                                    const GURL& new_page_url) {
2056   if (!thumbnail_db_)
2057     return;
2058
2059   // Prevent cross-domain cloning.
2060   if (old_page_url.GetOrigin() != new_page_url.GetOrigin())
2061     return;
2062
2063   thumbnail_db_->CloneIconMappings(old_page_url, new_page_url);
2064   ScheduleCommit();
2065 }
2066
2067 void HistoryBackend::SetImportedFavicons(
2068     const std::vector<ImportedFaviconUsage>& favicon_usage) {
2069   if (!db_ || !thumbnail_db_)
2070     return;
2071
2072   Time now = Time::Now();
2073
2074   // Track all URLs that had their favicons set or updated.
2075   std::set<GURL> favicons_changed;
2076
2077   for (size_t i = 0; i < favicon_usage.size(); i++) {
2078     chrome::FaviconID favicon_id = thumbnail_db_->GetFaviconIDForFaviconURL(
2079         favicon_usage[i].favicon_url, chrome::FAVICON, NULL);
2080     if (!favicon_id) {
2081       // This favicon doesn't exist yet, so we create it using the given data.
2082       // TODO(pkotwicz): Pass in real pixel size.
2083       favicon_id = thumbnail_db_->AddFavicon(
2084           favicon_usage[i].favicon_url,
2085           chrome::FAVICON,
2086           new base::RefCountedBytes(favicon_usage[i].png_data),
2087           now,
2088           gfx::Size());
2089     }
2090
2091     // Save the mapping from all the URLs to the favicon.
2092     BookmarkService* bookmark_service = GetBookmarkService();
2093     for (std::set<GURL>::const_iterator url = favicon_usage[i].urls.begin();
2094          url != favicon_usage[i].urls.end(); ++url) {
2095       URLRow url_row;
2096       if (!db_->GetRowForURL(*url, &url_row)) {
2097         // If the URL is present as a bookmark, add the url in history to
2098         // save the favicon mapping. This will match with what history db does
2099         // for regular bookmarked URLs with favicons - when history db is
2100         // cleaned, we keep an entry in the db with 0 visits as long as that
2101         // url is bookmarked.
2102         if (bookmark_service && bookmark_service_->IsBookmarked(*url)) {
2103           URLRow url_info(*url);
2104           url_info.set_visit_count(0);
2105           url_info.set_typed_count(0);
2106           url_info.set_last_visit(base::Time());
2107           url_info.set_hidden(false);
2108           db_->AddURL(url_info);
2109           thumbnail_db_->AddIconMapping(*url, favicon_id);
2110           favicons_changed.insert(*url);
2111         }
2112       } else {
2113         if (!thumbnail_db_->GetIconMappingsForPageURL(
2114                 *url, chrome::FAVICON, NULL)) {
2115           // URL is present in history, update the favicon *only* if it is not
2116           // set already.
2117           thumbnail_db_->AddIconMapping(*url, favicon_id);
2118           favicons_changed.insert(*url);
2119         }
2120       }
2121     }
2122   }
2123
2124   if (!favicons_changed.empty()) {
2125     // Send the notification about the changed favicon URLs.
2126     FaviconChangedDetails* changed_details = new FaviconChangedDetails;
2127     changed_details->urls.swap(favicons_changed);
2128     BroadcastNotifications(chrome::NOTIFICATION_FAVICON_CHANGED,
2129                            changed_details);
2130   }
2131 }
2132
2133 void HistoryBackend::UpdateFaviconMappingsAndFetchImpl(
2134     const GURL* page_url,
2135     const std::vector<GURL>& icon_urls,
2136     int icon_types,
2137     int desired_size_in_dip,
2138     const std::vector<ui::ScaleFactor>& desired_scale_factors,
2139     std::vector<chrome::FaviconBitmapResult>* bitmap_results) {
2140   // If |page_url| is specified, |icon_types| must be either a single icon
2141   // type or icon types which are equivalent.
2142   DCHECK(!page_url ||
2143          icon_types == chrome::FAVICON ||
2144          icon_types == chrome::TOUCH_ICON ||
2145          icon_types == chrome::TOUCH_PRECOMPOSED_ICON ||
2146          icon_types == (chrome::TOUCH_ICON | chrome::TOUCH_PRECOMPOSED_ICON));
2147   bitmap_results->clear();
2148
2149   if (!thumbnail_db_) {
2150     return;
2151   }
2152
2153   std::vector<chrome::FaviconID> favicon_ids;
2154
2155   // The icon type for which the mappings will the updated and data will be
2156   // returned.
2157   chrome::IconType selected_icon_type = chrome::INVALID_ICON;
2158
2159   for (size_t i = 0; i < icon_urls.size(); ++i) {
2160     const GURL& icon_url = icon_urls[i];
2161     chrome::IconType icon_type_out;
2162     const chrome::FaviconID favicon_id =
2163         thumbnail_db_->GetFaviconIDForFaviconURL(
2164             icon_url, icon_types, &icon_type_out);
2165
2166     if (favicon_id) {
2167       // Return and update icon mappings only for the largest icon type. As
2168       // |icon_urls| is not sorted in terms of icon type, clear |favicon_ids|
2169       // if an |icon_url| with a larger icon type is found.
2170       if (icon_type_out > selected_icon_type) {
2171         selected_icon_type = icon_type_out;
2172         favicon_ids.clear();
2173       }
2174       if (icon_type_out == selected_icon_type)
2175         favicon_ids.push_back(favicon_id);
2176     }
2177   }
2178
2179   if (page_url && !favicon_ids.empty()) {
2180     bool mappings_updated =
2181         SetFaviconMappingsForPageAndRedirects(*page_url, selected_icon_type,
2182                                               favicon_ids);
2183     if (mappings_updated) {
2184       SendFaviconChangedNotificationForPageAndRedirects(*page_url);
2185       ScheduleCommit();
2186     }
2187   }
2188
2189   GetFaviconBitmapResultsForBestMatch(favicon_ids, desired_size_in_dip,
2190       desired_scale_factors, bitmap_results);
2191 }
2192
2193 void HistoryBackend::SetFaviconBitmaps(
2194     chrome::FaviconID icon_id,
2195     const std::vector<chrome::FaviconBitmapData>& favicon_bitmap_data,
2196     bool* favicon_bitmaps_changed) {
2197   if (favicon_bitmaps_changed)
2198     *favicon_bitmaps_changed = false;
2199
2200   std::vector<FaviconBitmapIDSize> bitmap_id_sizes;
2201   thumbnail_db_->GetFaviconBitmapIDSizes(icon_id, &bitmap_id_sizes);
2202
2203   std::vector<chrome::FaviconBitmapData> to_add = favicon_bitmap_data;
2204
2205   for (size_t i = 0; i < bitmap_id_sizes.size(); ++i) {
2206     const gfx::Size& pixel_size = bitmap_id_sizes[i].pixel_size;
2207     std::vector<chrome::FaviconBitmapData>::iterator match_it = to_add.end();
2208     for (std::vector<chrome::FaviconBitmapData>::iterator it = to_add.begin();
2209          it != to_add.end(); ++it) {
2210       if (it->pixel_size == pixel_size) {
2211         match_it = it;
2212         break;
2213       }
2214     }
2215
2216     FaviconBitmapID bitmap_id = bitmap_id_sizes[i].bitmap_id;
2217     if (match_it == to_add.end()) {
2218       thumbnail_db_->DeleteFaviconBitmap(bitmap_id);
2219
2220       if (favicon_bitmaps_changed)
2221         *favicon_bitmaps_changed = true;
2222     } else {
2223       if (favicon_bitmaps_changed &&
2224           !*favicon_bitmaps_changed &&
2225           IsFaviconBitmapDataEqual(bitmap_id, match_it->bitmap_data)) {
2226         thumbnail_db_->SetFaviconBitmapLastUpdateTime(
2227             bitmap_id, base::Time::Now());
2228       } else {
2229         thumbnail_db_->SetFaviconBitmap(bitmap_id, match_it->bitmap_data,
2230             base::Time::Now());
2231
2232         if (favicon_bitmaps_changed)
2233           *favicon_bitmaps_changed = true;
2234       }
2235       to_add.erase(match_it);
2236     }
2237   }
2238
2239   for (size_t i = 0; i < to_add.size(); ++i) {
2240     thumbnail_db_->AddFaviconBitmap(icon_id, to_add[i].bitmap_data,
2241         base::Time::Now(), to_add[i].pixel_size);
2242
2243     if (favicon_bitmaps_changed)
2244       *favicon_bitmaps_changed = true;
2245   }
2246 }
2247
2248 bool HistoryBackend::ValidateSetFaviconsParams(
2249     const std::vector<chrome::FaviconBitmapData>& favicon_bitmap_data) const {
2250   typedef std::map<GURL, size_t> BitmapsPerIconURL;
2251   BitmapsPerIconURL num_bitmaps_per_icon_url;
2252   for (size_t i = 0; i < favicon_bitmap_data.size(); ++i) {
2253     if (!favicon_bitmap_data[i].bitmap_data.get())
2254       return false;
2255
2256     const GURL& icon_url = favicon_bitmap_data[i].icon_url;
2257     if (!num_bitmaps_per_icon_url.count(icon_url))
2258       num_bitmaps_per_icon_url[icon_url] = 1u;
2259     else
2260       ++num_bitmaps_per_icon_url[icon_url];
2261   }
2262
2263   if (num_bitmaps_per_icon_url.size() > kMaxFaviconsPerPage)
2264     return false;
2265
2266   for (BitmapsPerIconURL::const_iterator it = num_bitmaps_per_icon_url.begin();
2267        it != num_bitmaps_per_icon_url.end(); ++it) {
2268     if (it->second > kMaxFaviconBitmapsPerIconURL)
2269       return false;
2270   }
2271   return true;
2272 }
2273
2274 bool HistoryBackend::IsFaviconBitmapDataEqual(
2275     FaviconBitmapID bitmap_id,
2276     const scoped_refptr<base::RefCountedMemory>& new_bitmap_data) {
2277   if (!new_bitmap_data.get())
2278     return false;
2279
2280   scoped_refptr<base::RefCountedMemory> original_bitmap_data;
2281   thumbnail_db_->GetFaviconBitmap(bitmap_id,
2282                                   NULL,
2283                                   &original_bitmap_data,
2284                                   NULL);
2285   return new_bitmap_data->Equals(original_bitmap_data);
2286 }
2287
2288 bool HistoryBackend::GetFaviconsFromDB(
2289     const GURL& page_url,
2290     int icon_types,
2291     int desired_size_in_dip,
2292     const std::vector<ui::ScaleFactor>& desired_scale_factors,
2293     std::vector<chrome::FaviconBitmapResult>* favicon_bitmap_results) {
2294   DCHECK(favicon_bitmap_results);
2295   favicon_bitmap_results->clear();
2296
2297   if (!db_ || !thumbnail_db_)
2298     return false;
2299
2300   // Time the query.
2301   TimeTicks beginning_time = TimeTicks::Now();
2302
2303   // Get FaviconIDs for |page_url| and one of |icon_types|.
2304   std::vector<IconMapping> icon_mappings;
2305   thumbnail_db_->GetIconMappingsForPageURL(page_url, icon_types,
2306                                            &icon_mappings);
2307   std::vector<chrome::FaviconID> favicon_ids;
2308   for (size_t i = 0; i < icon_mappings.size(); ++i)
2309     favicon_ids.push_back(icon_mappings[i].icon_id);
2310
2311   // Populate |favicon_bitmap_results| and |icon_url_sizes|.
2312   bool success = GetFaviconBitmapResultsForBestMatch(favicon_ids,
2313       desired_size_in_dip, desired_scale_factors, favicon_bitmap_results);
2314   UMA_HISTOGRAM_TIMES("History.GetFavIconFromDB",  // historical name
2315                       TimeTicks::Now() - beginning_time);
2316   return success && !favicon_bitmap_results->empty();
2317 }
2318
2319 bool HistoryBackend::GetFaviconBitmapResultsForBestMatch(
2320     const std::vector<chrome::FaviconID>& candidate_favicon_ids,
2321     int desired_size_in_dip,
2322     const std::vector<ui::ScaleFactor>& desired_scale_factors,
2323     std::vector<chrome::FaviconBitmapResult>* favicon_bitmap_results) {
2324   favicon_bitmap_results->clear();
2325
2326   if (candidate_favicon_ids.empty())
2327     return true;
2328
2329   // Find the FaviconID and the FaviconBitmapIDs which best match
2330   // |desired_size_in_dip| and |desired_scale_factors|.
2331   // TODO(pkotwicz): Select bitmap results from multiple favicons once
2332   // content::FaviconStatus supports multiple icon URLs.
2333   chrome::FaviconID best_favicon_id = 0;
2334   std::vector<FaviconBitmapID> best_bitmap_ids;
2335   float highest_score = kSelectFaviconFramesInvalidScore;
2336   for (size_t i = 0; i < candidate_favicon_ids.size(); ++i) {
2337     std::vector<FaviconBitmapIDSize> bitmap_id_sizes;
2338     thumbnail_db_->GetFaviconBitmapIDSizes(candidate_favicon_ids[i],
2339                                            &bitmap_id_sizes);
2340
2341     // Build vector of gfx::Size from |bitmap_id_sizes|.
2342     std::vector<gfx::Size> sizes;
2343     for (size_t j = 0; j < bitmap_id_sizes.size(); ++j)
2344       sizes.push_back(bitmap_id_sizes[j].pixel_size);
2345
2346     std::vector<size_t> candidate_bitmap_indices;
2347     float score = 0;
2348     SelectFaviconFrameIndices(sizes,
2349                               desired_scale_factors,
2350                               desired_size_in_dip,
2351                               &candidate_bitmap_indices,
2352                               &score);
2353     if (score > highest_score) {
2354       highest_score = score;
2355       best_favicon_id = candidate_favicon_ids[i],
2356       best_bitmap_ids.clear();
2357       for (size_t j = 0; j < candidate_bitmap_indices.size(); ++j) {
2358         size_t candidate_index = candidate_bitmap_indices[j];
2359         best_bitmap_ids.push_back(
2360             bitmap_id_sizes[candidate_index].bitmap_id);
2361       }
2362     }
2363   }
2364
2365   // Construct FaviconBitmapResults from |best_favicon_id| and
2366   // |best_bitmap_ids|.
2367   GURL icon_url;
2368   chrome::IconType icon_type;
2369   if (!thumbnail_db_->GetFaviconHeader(best_favicon_id, &icon_url,
2370                                        &icon_type)) {
2371     return false;
2372   }
2373
2374   for (size_t i = 0; i < best_bitmap_ids.size(); ++i) {
2375     base::Time last_updated;
2376     chrome::FaviconBitmapResult bitmap_result;
2377     bitmap_result.icon_url = icon_url;
2378     bitmap_result.icon_type = icon_type;
2379     if (!thumbnail_db_->GetFaviconBitmap(best_bitmap_ids[i],
2380                                          &last_updated,
2381                                          &bitmap_result.bitmap_data,
2382                                          &bitmap_result.pixel_size)) {
2383       return false;
2384     }
2385
2386     bitmap_result.expired = (Time::Now() - last_updated) >
2387         TimeDelta::FromDays(kFaviconRefetchDays);
2388     if (bitmap_result.is_valid())
2389       favicon_bitmap_results->push_back(bitmap_result);
2390   }
2391   return true;
2392 }
2393
2394 bool HistoryBackend::SetFaviconMappingsForPageAndRedirects(
2395     const GURL& page_url,
2396     chrome::IconType icon_type,
2397     const std::vector<chrome::FaviconID>& icon_ids) {
2398   if (!thumbnail_db_)
2399     return false;
2400
2401   // Find all the pages whose favicons we should set, we want to set it for
2402   // all the pages in the redirect chain if it redirected.
2403   history::RedirectList redirects;
2404   GetCachedRecentRedirects(page_url, &redirects);
2405
2406   bool mappings_changed = false;
2407
2408   // Save page <-> favicon associations.
2409   for (history::RedirectList::const_iterator i(redirects.begin());
2410        i != redirects.end(); ++i) {
2411     mappings_changed |= SetFaviconMappingsForPage(*i, icon_type, icon_ids);
2412   }
2413   return mappings_changed;
2414 }
2415
2416 bool HistoryBackend::SetFaviconMappingsForPage(
2417     const GURL& page_url,
2418     chrome::IconType icon_type,
2419     const std::vector<chrome::FaviconID>& icon_ids) {
2420   DCHECK_LE(icon_ids.size(), kMaxFaviconsPerPage);
2421   bool mappings_changed = false;
2422
2423   // Two icon types are considered 'equivalent' if one of the icon types is
2424   // TOUCH_ICON and the other is TOUCH_PRECOMPOSED_ICON.
2425   //
2426   // Sets the icon mappings from |page_url| for |icon_type| to the favicons
2427   // with |icon_ids|. Mappings for |page_url| to favicons of type |icon_type|
2428   // whose FaviconID is not in |icon_ids| are removed. All icon mappings for
2429   // |page_url| to favicons of a type equivalent to |icon_type| are removed.
2430   // Remove any favicons which are orphaned as a result of the removal of the
2431   // icon mappings.
2432
2433   std::vector<chrome::FaviconID> unmapped_icon_ids = icon_ids;
2434
2435   std::vector<IconMapping> icon_mappings;
2436   thumbnail_db_->GetIconMappingsForPageURL(page_url, &icon_mappings);
2437
2438   for (std::vector<IconMapping>::iterator m = icon_mappings.begin();
2439        m != icon_mappings.end(); ++m) {
2440     std::vector<chrome::FaviconID>::iterator icon_id_it = std::find(
2441         unmapped_icon_ids.begin(), unmapped_icon_ids.end(), m->icon_id);
2442
2443     // If the icon mapping already exists, avoid removing it and adding it back.
2444     if (icon_id_it != unmapped_icon_ids.end()) {
2445       unmapped_icon_ids.erase(icon_id_it);
2446       continue;
2447     }
2448
2449     if ((icon_type == chrome::TOUCH_ICON &&
2450          m->icon_type == chrome::TOUCH_PRECOMPOSED_ICON) ||
2451         (icon_type == chrome::TOUCH_PRECOMPOSED_ICON &&
2452          m->icon_type == chrome::TOUCH_ICON) || (icon_type == m->icon_type)) {
2453       thumbnail_db_->DeleteIconMapping(m->mapping_id);
2454
2455       // Removing the icon mapping may have orphaned the associated favicon so
2456       // we must recheck it. This is not super fast, but this case will get
2457       // triggered rarely, since normally a page will always map to the same
2458       // favicon IDs. It will mostly happen for favicons we import.
2459       if (!thumbnail_db_->HasMappingFor(m->icon_id))
2460         thumbnail_db_->DeleteFavicon(m->icon_id);
2461       mappings_changed = true;
2462     }
2463   }
2464
2465   for (size_t i = 0; i < unmapped_icon_ids.size(); ++i) {
2466     thumbnail_db_->AddIconMapping(page_url, unmapped_icon_ids[i]);
2467     mappings_changed = true;
2468   }
2469   return mappings_changed;
2470 }
2471
2472 void HistoryBackend::GetCachedRecentRedirects(
2473     const GURL& page_url,
2474     history::RedirectList* redirect_list) {
2475   RedirectCache::iterator iter = recent_redirects_.Get(page_url);
2476   if (iter != recent_redirects_.end()) {
2477     *redirect_list = iter->second;
2478
2479     // The redirect chain should have the destination URL as the last item.
2480     DCHECK(!redirect_list->empty());
2481     DCHECK(redirect_list->back() == page_url);
2482   } else {
2483     // No known redirects, construct mock redirect chain containing |page_url|.
2484     redirect_list->push_back(page_url);
2485   }
2486 }
2487
2488 void HistoryBackend::SendFaviconChangedNotificationForPageAndRedirects(
2489     const GURL& page_url) {
2490   history::RedirectList redirect_list;
2491   GetCachedRecentRedirects(page_url, &redirect_list);
2492
2493   FaviconChangedDetails* changed_details = new FaviconChangedDetails;
2494   for (size_t i = 0; i < redirect_list.size(); ++i)
2495     changed_details->urls.insert(redirect_list[i]);
2496
2497   BroadcastNotifications(chrome::NOTIFICATION_FAVICON_CHANGED,
2498                          changed_details);
2499 }
2500
2501 void HistoryBackend::Commit() {
2502   if (!db_)
2503     return;
2504
2505   // Note that a commit may not actually have been scheduled if a caller
2506   // explicitly calls this instead of using ScheduleCommit. Likewise, we
2507   // may reset the flag written by a pending commit. But this is OK! It
2508   // will merely cause extra commits (which is kind of the idea). We
2509   // could optimize more for this case (we may get two extra commits in
2510   // some cases) but it hasn't been important yet.
2511   CancelScheduledCommit();
2512
2513   db_->CommitTransaction();
2514   DCHECK(db_->transaction_nesting() == 0) << "Somebody left a transaction open";
2515   db_->BeginTransaction();
2516
2517   if (thumbnail_db_) {
2518     thumbnail_db_->CommitTransaction();
2519     DCHECK(thumbnail_db_->transaction_nesting() == 0) <<
2520         "Somebody left a transaction open";
2521     thumbnail_db_->BeginTransaction();
2522   }
2523
2524   if (archived_db_) {
2525     archived_db_->CommitTransaction();
2526     archived_db_->BeginTransaction();
2527   }
2528 }
2529
2530 void HistoryBackend::ScheduleCommit() {
2531   if (scheduled_commit_.get())
2532     return;
2533   scheduled_commit_ = new CommitLaterTask(this);
2534   base::MessageLoop::current()->PostDelayedTask(
2535       FROM_HERE,
2536       base::Bind(&CommitLaterTask::RunCommit, scheduled_commit_.get()),
2537       base::TimeDelta::FromSeconds(kCommitIntervalSeconds));
2538 }
2539
2540 void HistoryBackend::CancelScheduledCommit() {
2541   if (scheduled_commit_.get()) {
2542     scheduled_commit_->Cancel();
2543     scheduled_commit_ = NULL;
2544   }
2545 }
2546
2547 void HistoryBackend::ProcessDBTaskImpl() {
2548   if (!db_) {
2549     // db went away, release all the refs.
2550     ReleaseDBTasks();
2551     return;
2552   }
2553
2554   // Remove any canceled tasks.
2555   while (!db_task_requests_.empty() && db_task_requests_.front()->canceled()) {
2556     db_task_requests_.front()->Release();
2557     db_task_requests_.pop_front();
2558   }
2559   if (db_task_requests_.empty())
2560     return;
2561
2562   // Run the first task.
2563   HistoryDBTaskRequest* request = db_task_requests_.front();
2564   db_task_requests_.pop_front();
2565   if (request->value->RunOnDBThread(this, db_.get())) {
2566     // The task is done. Notify the callback.
2567     request->ForwardResult();
2568     // We AddRef'd the request before adding, need to release it now.
2569     request->Release();
2570   } else {
2571     // Tasks wants to run some more. Schedule it at the end of current tasks.
2572     db_task_requests_.push_back(request);
2573     // And process it after an invoke later.
2574     base::MessageLoop::current()->PostTask(
2575         FROM_HERE, base::Bind(&HistoryBackend::ProcessDBTaskImpl, this));
2576   }
2577 }
2578
2579 void HistoryBackend::ReleaseDBTasks() {
2580   for (std::list<HistoryDBTaskRequest*>::iterator i =
2581        db_task_requests_.begin(); i != db_task_requests_.end(); ++i) {
2582     (*i)->Release();
2583   }
2584   db_task_requests_.clear();
2585 }
2586
2587 ////////////////////////////////////////////////////////////////////////////////
2588 //
2589 // Generic operations
2590 //
2591 ////////////////////////////////////////////////////////////////////////////////
2592
2593 void HistoryBackend::DeleteURLs(const std::vector<GURL>& urls) {
2594   expirer_.DeleteURLs(urls);
2595
2596   db_->GetStartDate(&first_recorded_time_);
2597   // Force a commit, if the user is deleting something for privacy reasons, we
2598   // want to get it on disk ASAP.
2599   Commit();
2600 }
2601
2602 void HistoryBackend::DeleteURL(const GURL& url) {
2603   expirer_.DeleteURL(url);
2604
2605   db_->GetStartDate(&first_recorded_time_);
2606   // Force a commit, if the user is deleting something for privacy reasons, we
2607   // want to get it on disk ASAP.
2608   Commit();
2609 }
2610
2611 void HistoryBackend::ExpireHistoryBetween(
2612     const std::set<GURL>& restrict_urls,
2613     Time begin_time,
2614     Time end_time) {
2615   if (!db_)
2616     return;
2617
2618   if (begin_time.is_null() && (end_time.is_null() || end_time.is_max()) &&
2619       restrict_urls.empty()) {
2620     // Special case deleting all history so it can be faster and to reduce the
2621     // possibility of an information leak.
2622     DeleteAllHistory();
2623   } else {
2624     // Clearing parts of history, have the expirer do the depend
2625     expirer_.ExpireHistoryBetween(restrict_urls, begin_time, end_time);
2626
2627     // Force a commit, if the user is deleting something for privacy reasons,
2628     // we want to get it on disk ASAP.
2629     Commit();
2630   }
2631
2632   if (begin_time <= first_recorded_time_)
2633     db_->GetStartDate(&first_recorded_time_);
2634 }
2635
2636 void HistoryBackend::ExpireHistoryForTimes(
2637     const std::set<base::Time>& times,
2638     base::Time begin_time, base::Time end_time) {
2639   if (times.empty() || !db_)
2640     return;
2641
2642   DCHECK(*times.begin() >= begin_time)
2643       << "Min time is before begin time: "
2644       << times.begin()->ToJsTime() << " v.s. " << begin_time.ToJsTime();
2645   DCHECK(*times.rbegin() < end_time)
2646       << "Max time is after end time: "
2647       << times.rbegin()->ToJsTime() << " v.s. " << end_time.ToJsTime();
2648
2649   history::QueryOptions options;
2650   options.begin_time = begin_time;
2651   options.end_time = end_time;
2652   options.duplicate_policy = QueryOptions::KEEP_ALL_DUPLICATES;
2653   QueryResults results;
2654   QueryHistoryBasic(db_.get(), db_.get(), options, &results);
2655
2656   // 1st pass: find URLs that are visited at one of |times|.
2657   std::set<GURL> urls;
2658   for (size_t i = 0; i < results.size(); ++i) {
2659     if (times.count(results[i].visit_time()) > 0)
2660       urls.insert(results[i].url());
2661   }
2662   if (urls.empty())
2663     return;
2664
2665   // 2nd pass: collect all visit times of those URLs.
2666   std::vector<base::Time> times_to_expire;
2667   for (size_t i = 0; i < results.size(); ++i) {
2668     if (urls.count(results[i].url()))
2669       times_to_expire.push_back(results[i].visit_time());
2670   }
2671
2672   // Put the times in reverse chronological order and remove
2673   // duplicates (for expirer_.ExpireHistoryForTimes()).
2674   std::sort(times_to_expire.begin(), times_to_expire.end(),
2675             std::greater<base::Time>());
2676   times_to_expire.erase(
2677       std::unique(times_to_expire.begin(), times_to_expire.end()),
2678       times_to_expire.end());
2679
2680   // Expires by times and commit.
2681   DCHECK(!times_to_expire.empty());
2682   expirer_.ExpireHistoryForTimes(times_to_expire);
2683   Commit();
2684
2685   DCHECK(times_to_expire.back() >= first_recorded_time_);
2686   // Update |first_recorded_time_| if we expired it.
2687   if (times_to_expire.back() == first_recorded_time_)
2688     db_->GetStartDate(&first_recorded_time_);
2689 }
2690
2691 void HistoryBackend::ExpireHistory(
2692     const std::vector<history::ExpireHistoryArgs>& expire_list) {
2693   if (db_) {
2694     bool update_first_recorded_time = false;
2695
2696     for (std::vector<history::ExpireHistoryArgs>::const_iterator it =
2697          expire_list.begin(); it != expire_list.end(); ++it) {
2698       expirer_.ExpireHistoryBetween(it->urls, it->begin_time, it->end_time);
2699
2700       if (it->begin_time < first_recorded_time_)
2701         update_first_recorded_time = true;
2702     }
2703     Commit();
2704
2705     // Update |first_recorded_time_| if any deletion might have affected it.
2706     if (update_first_recorded_time)
2707       db_->GetStartDate(&first_recorded_time_);
2708   }
2709 }
2710
2711 void HistoryBackend::URLsNoLongerBookmarked(const std::set<GURL>& urls) {
2712   if (!db_)
2713     return;
2714
2715   for (std::set<GURL>::const_iterator i = urls.begin(); i != urls.end(); ++i) {
2716     URLRow url_row;
2717     if (!db_->GetRowForURL(*i, &url_row))
2718       continue;  // The URL isn't in the db; nothing to do.
2719
2720     VisitVector visits;
2721     db_->GetVisitsForURL(url_row.id(), &visits);
2722
2723     if (visits.empty())
2724       expirer_.DeleteURL(*i);  // There are no more visits; nuke the URL.
2725   }
2726 }
2727
2728 void HistoryBackend::DatabaseErrorCallback(int error, sql::Statement* stmt) {
2729   if (!scheduled_kill_db_ && sql::IsErrorCatastrophic(error)) {
2730     scheduled_kill_db_ = true;
2731     // Don't just do the close/delete here, as we are being called by |db| and
2732     // that seems dangerous.
2733     // TODO(shess): Consider changing KillHistoryDatabase() to use
2734     // RazeAndClose().  Then it can be cleared immediately.
2735     base::MessageLoop::current()->PostTask(
2736         FROM_HERE,
2737         base::Bind(&HistoryBackend::KillHistoryDatabase, this));
2738   }
2739 }
2740
2741 void HistoryBackend::KillHistoryDatabase() {
2742   scheduled_kill_db_ = false;
2743   if (!db_)
2744     return;
2745
2746   // Rollback transaction because Raze() cannot be called from within a
2747   // transaction.
2748   db_->RollbackTransaction();
2749   bool success = db_->Raze();
2750   UMA_HISTOGRAM_BOOLEAN("History.KillHistoryDatabaseResult", success);
2751
2752 #if defined(OS_ANDROID)
2753   // Release AndroidProviderBackend before other objects.
2754   android_provider_backend_.reset();
2755 #endif
2756
2757   // The expirer keeps tabs on the active databases. Tell it about the
2758   // databases which will be closed.
2759   expirer_.SetDatabases(NULL, NULL, NULL);
2760
2761   // Reopen a new transaction for |db_| for the sake of CloseAllDatabases().
2762   db_->BeginTransaction();
2763   CloseAllDatabases();
2764 }
2765
2766 void HistoryBackend::ProcessDBTask(
2767     scoped_refptr<HistoryDBTaskRequest> request) {
2768   DCHECK(request.get());
2769   if (request->canceled())
2770     return;
2771
2772   bool task_scheduled = !db_task_requests_.empty();
2773   // Make sure we up the refcount of the request. ProcessDBTaskImpl will
2774   // release when done with the task.
2775   request->AddRef();
2776   db_task_requests_.push_back(request.get());
2777   if (!task_scheduled) {
2778     // No other tasks are scheduled. Process request now.
2779     ProcessDBTaskImpl();
2780   }
2781 }
2782
2783 void HistoryBackend::BroadcastNotifications(
2784     int type,
2785     HistoryDetails* details_deleted) {
2786   // |delegate_| may be NULL if |this| is in the process of closing (closed by
2787   // HistoryService -> HistoryBackend::Closing().
2788   if (delegate_)
2789     delegate_->BroadcastNotifications(type, details_deleted);
2790   else
2791     delete details_deleted;
2792 }
2793
2794 void HistoryBackend::NotifySyncURLsDeleted(bool all_history,
2795                                            bool archived,
2796                                            URLRows* rows) {
2797   if (typed_url_syncable_service_.get())
2798     typed_url_syncable_service_->OnUrlsDeleted(all_history, archived, rows);
2799 }
2800
2801 // Deleting --------------------------------------------------------------------
2802
2803 void HistoryBackend::DeleteAllHistory() {
2804   // Our approach to deleting all history is:
2805   //  1. Copy the bookmarks and their dependencies to new tables with temporary
2806   //     names.
2807   //  2. Delete the original tables. Since tables can not share pages, we know
2808   //     that any data we don't want to keep is now in an unused page.
2809   //  3. Renaming the temporary tables to match the original.
2810   //  4. Vacuuming the database to delete the unused pages.
2811   //
2812   // Since we are likely to have very few bookmarks and their dependencies
2813   // compared to all history, this is also much faster than just deleting from
2814   // the original tables directly.
2815
2816   // Get the bookmarked URLs.
2817   std::vector<BookmarkService::URLAndTitle> starred_urls;
2818   BookmarkService* bookmark_service = GetBookmarkService();
2819   if (bookmark_service)
2820     bookmark_service_->GetBookmarks(&starred_urls);
2821
2822   URLRows kept_urls;
2823   for (size_t i = 0; i < starred_urls.size(); i++) {
2824     URLRow row;
2825     if (!db_->GetRowForURL(starred_urls[i].url, &row))
2826       continue;
2827
2828     // Clear the last visit time so when we write these rows they are "clean."
2829     row.set_last_visit(Time());
2830     row.set_visit_count(0);
2831     row.set_typed_count(0);
2832     kept_urls.push_back(row);
2833   }
2834
2835   // Clear thumbnail and favicon history. The favicons for the given URLs will
2836   // be kept.
2837   if (!ClearAllThumbnailHistory(kept_urls)) {
2838     LOG(ERROR) << "Thumbnail history could not be cleared";
2839     // We continue in this error case. If the user wants to delete their
2840     // history, we should delete as much as we can.
2841   }
2842
2843   // ClearAllMainHistory will change the IDs of the URLs in kept_urls.
2844   // Therefore, we clear the list afterwards to make sure nobody uses this
2845   // invalid data.
2846   if (!ClearAllMainHistory(kept_urls))
2847     LOG(ERROR) << "Main history could not be cleared";
2848   kept_urls.clear();
2849
2850   // Delete archived history.
2851   if (archived_db_) {
2852     // Close the database and delete the file.
2853     archived_db_.reset();
2854     base::FilePath archived_file_name = GetArchivedFileName();
2855     sql::Connection::Delete(archived_file_name);
2856
2857     // Now re-initialize the database (which may fail).
2858     archived_db_.reset(new ArchivedDatabase());
2859     if (!archived_db_->Init(archived_file_name)) {
2860       LOG(WARNING) << "Could not initialize the archived database.";
2861       archived_db_.reset();
2862     } else {
2863       // Open our long-running transaction on this database.
2864       archived_db_->BeginTransaction();
2865     }
2866   }
2867
2868   db_->GetStartDate(&first_recorded_time_);
2869
2870   // Send out the notification that history is cleared. The in-memory database
2871   // will pick this up and clear itself.
2872   URLsDeletedDetails* details = new URLsDeletedDetails;
2873   details->all_history = true;
2874   NotifySyncURLsDeleted(true, false, NULL);
2875   BroadcastNotifications(chrome::NOTIFICATION_HISTORY_URLS_DELETED, details);
2876 }
2877
2878 bool HistoryBackend::ClearAllThumbnailHistory(const URLRows& kept_urls) {
2879   if (!thumbnail_db_) {
2880     // When we have no reference to the thumbnail database, maybe there was an
2881     // error opening it. In this case, we just try to blow it away to try to
2882     // fix the error if it exists. This may fail, in which case either the
2883     // file doesn't exist or there's no more we can do.
2884     sql::Connection::Delete(GetFaviconsFileName());
2885
2886     // Older version of the database.
2887     sql::Connection::Delete(GetThumbnailFileName());
2888     return true;
2889   }
2890
2891   // Urls to retain mappings for.
2892   std::vector<GURL> urls_to_keep;
2893   for (URLRows::const_iterator i = kept_urls.begin();
2894        i != kept_urls.end(); ++i) {
2895     urls_to_keep.push_back(i->url());
2896   }
2897
2898   // Isolate from any long-running transaction.
2899   thumbnail_db_->CommitTransaction();
2900   thumbnail_db_->BeginTransaction();
2901
2902   // TODO(shess): If this fails, perhaps the database should be razed
2903   // or deleted.
2904   if (!thumbnail_db_->RetainDataForPageUrls(urls_to_keep)) {
2905     thumbnail_db_->RollbackTransaction();
2906     thumbnail_db_->BeginTransaction();
2907     return false;
2908   }
2909
2910 #if defined(OS_ANDROID)
2911   // TODO (michaelbai): Add the unit test once AndroidProviderBackend is
2912   // avaliable in HistoryBackend.
2913   db_->ClearAndroidURLRows();
2914 #endif
2915
2916   // Vacuum to remove all the pages associated with the dropped tables. There
2917   // must be no transaction open on the table when we do this. We assume that
2918   // our long-running transaction is open, so we complete it and start it again.
2919   DCHECK(thumbnail_db_->transaction_nesting() == 1);
2920   thumbnail_db_->CommitTransaction();
2921   thumbnail_db_->Vacuum();
2922   thumbnail_db_->BeginTransaction();
2923   return true;
2924 }
2925
2926 bool HistoryBackend::ClearAllMainHistory(const URLRows& kept_urls) {
2927   // Create the duplicate URL table. We will copy the kept URLs into this.
2928   if (!db_->CreateTemporaryURLTable())
2929     return false;
2930
2931   // Insert the URLs into the temporary table.
2932   for (URLRows::const_iterator i = kept_urls.begin(); i != kept_urls.end();
2933        ++i) {
2934     db_->AddTemporaryURL(*i);
2935   }
2936
2937   // Replace the original URL table with the temporary one.
2938   if (!db_->CommitTemporaryURLTable())
2939     return false;
2940
2941   // Delete the old tables and recreate them empty.
2942   db_->RecreateAllTablesButURL();
2943
2944   // Vacuum to reclaim the space from the dropped tables. This must be done
2945   // when there is no transaction open, and we assume that our long-running
2946   // transaction is currently open.
2947   db_->CommitTransaction();
2948   db_->Vacuum();
2949   db_->BeginTransaction();
2950   db_->GetStartDate(&first_recorded_time_);
2951
2952   return true;
2953 }
2954
2955 BookmarkService* HistoryBackend::GetBookmarkService() {
2956   if (bookmark_service_)
2957     bookmark_service_->BlockTillLoaded();
2958   return bookmark_service_;
2959 }
2960
2961 void HistoryBackend::NotifyVisitObservers(const VisitRow& visit) {
2962   BriefVisitInfo info;
2963   info.url_id = visit.url_id;
2964   info.time = visit.visit_time;
2965   info.transition = visit.transition;
2966   // If we don't have a delegate yet during setup or shutdown, we will drop
2967   // these notifications.
2968   if (delegate_)
2969     delegate_->NotifyVisitDBObserversOnAddVisit(info);
2970 }
2971
2972 #if defined(OS_ANDROID)
2973 void HistoryBackend::PopulateMostVisitedURLMap() {
2974   MostVisitedURLList most_visited_urls;
2975   QueryMostVisitedURLsImpl(kPageVisitStatsMaxTopSites, kSegmentDataRetention,
2976                            &most_visited_urls);
2977
2978   DCHECK_LE(most_visited_urls.size(), kPageVisitStatsMaxTopSites);
2979   for (size_t i = 0; i < most_visited_urls.size(); ++i) {
2980     most_visited_urls_map_[most_visited_urls[i].url] = i;
2981     for (size_t j = 0; j < most_visited_urls[i].redirects.size(); ++j)
2982       most_visited_urls_map_[most_visited_urls[i].redirects[j]] = i;
2983   }
2984 }
2985
2986 void HistoryBackend::RecordTopPageVisitStats(const GURL& url) {
2987   int rank = kPageVisitStatsMaxTopSites;
2988   std::map<GURL, int>::const_iterator it = most_visited_urls_map_.find(url);
2989   if (it != most_visited_urls_map_.end())
2990     rank = (*it).second;
2991   UMA_HISTOGRAM_ENUMERATION("History.TopSitesVisitsByRank",
2992                             rank, kPageVisitStatsMaxTopSites + 1);
2993 }
2994 #endif
2995
2996 }  // namespace history