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