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