15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// DownloadHistory manages persisting DownloadItems to the history service by
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// observing a single DownloadManager and all its DownloadItems using an
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// AllDownloadItemNotifier.
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)//
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// DownloadHistory decides whether and when to add items to, remove items from,
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// and update items in the database. DownloadHistory uses DownloadHistoryData to
117dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// store per-DownloadItem data such as whether the item is persisted or being
127dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// persisted, and the last history::DownloadRow that was passed to the database.
137dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// When the DownloadManager and its delegate (ChromeDownloadManagerDelegate) are
147dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// initialized, DownloadHistory is created and queries the HistoryService. When
157dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// the HistoryService calls back from QueryDownloads() to QueryCallback(),
167dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// DownloadHistory uses DownloadManager::CreateDownloadItem() to inform
177dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// DownloadManager of these persisted DownloadItems. CreateDownloadItem()
187dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// internally calls OnDownloadCreated(), which normally adds items to the
197dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// database, so QueryCallback() uses |loading_id_| to disable adding these items
207dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// to the database.  If a download is removed via OnDownloadRemoved() while the
217dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// item is still being added to the database, DownloadHistory uses
227dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// |removed_while_adding_| to remember to remove the item when its ItemAdded()
237dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// callback is called.  All callbacks are bound with a weak pointer to
247dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// DownloadHistory to prevent use-after-free bugs.
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// ChromeDownloadManagerDelegate owns DownloadHistory, and deletes it in
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Shutdown(), which is called by DownloadManagerImpl::Shutdown() after all
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// DownloadItems are destroyed.
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/download/download_history.h"
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/metrics/histogram.h"
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/download/download_crx_util.h"
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/history/download_database.h"
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/history/download_row.h"
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/history/history_service.h"
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/browser_thread.h"
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/download_item.h"
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/download_manager.h"
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#if defined(ENABLE_EXTENSIONS)
41a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "chrome/browser/extensions/api/downloads/downloads_api.h"
42a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#endif
43a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Per-DownloadItem data. This information does not belong inside DownloadItem,
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// and keeping maps in DownloadHistory from DownloadItem to this information is
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// error-prone and complicated. Unfortunately, DownloadHistory::removing_*_ and
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// removed_while_adding_ cannot be moved into this class partly because
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// DownloadHistoryData is destroyed when DownloadItems are destroyed, and we
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// have no control over when DownloadItems are destroyed.
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class DownloadHistoryData : public base::SupportsUserData::Data {
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public:
547dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  enum PersistenceState {
557dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    NOT_PERSISTED,
567dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    PERSISTING,
577dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    PERSISTED,
587dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  };
597dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  static DownloadHistoryData* Get(content::DownloadItem* item) {
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::SupportsUserData::Data* data = item->GetUserData(kKey);
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return (data == NULL) ? NULL :
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      static_cast<DownloadHistoryData*>(data);
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
66cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  static const DownloadHistoryData* Get(const content::DownloadItem* item) {
67cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const base::SupportsUserData::Data* data = item->GetUserData(kKey);
68cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return (data == NULL) ? NULL
69cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                          : static_cast<const DownloadHistoryData*>(data);
70cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
71cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
727dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  explicit DownloadHistoryData(content::DownloadItem* item)
73cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      : state_(NOT_PERSISTED),
74cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        was_restored_from_history_(false) {
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    item->SetUserData(kKey, this);
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual ~DownloadHistoryData() {
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
817dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  PersistenceState state() const { return state_; }
827dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  void SetState(PersistenceState s) { state_ = s; }
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
84cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  bool was_restored_from_history() const { return was_restored_from_history_; }
85cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  void set_was_restored_from_history(bool value) {
86cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    was_restored_from_history_ = value;
87cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
88cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // This allows DownloadHistory::OnDownloadUpdated() to see what changed in a
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // DownloadItem if anything, in order to prevent writing to the database
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // unnecessarily.  It is nullified when the item is no longer in progress in
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // order to save memory.
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  history::DownloadRow* info() { return info_.get(); }
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void set_info(const history::DownloadRow& i) {
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    info_.reset(new history::DownloadRow(i));
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void clear_info() {
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    info_.reset();
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private:
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  static const char kKey[];
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1047dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  PersistenceState state_;
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<history::DownloadRow> info_;
106cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  bool was_restored_from_history_;
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(DownloadHistoryData);
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char DownloadHistoryData::kKey[] =
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  "DownloadItem DownloadHistoryData";
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)history::DownloadRow GetDownloadRow(
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    content::DownloadItem* item) {
116a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  std::string by_ext_id, by_ext_name;
11746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#if defined(ENABLE_EXTENSIONS)
1185c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  extensions::DownloadedByExtension* by_ext =
1195c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      extensions::DownloadedByExtension::Get(item);
120a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (by_ext) {
121a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    by_ext_id = by_ext->id();
122a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    by_ext_name = by_ext->name();
123a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  }
124a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#endif
125a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return history::DownloadRow(
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      item->GetFullPath(),
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      item->GetTargetFilePath(),
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      item->GetUrlChain(),
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      item->GetReferrerUrl(),
131f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      item->GetMimeType(),
132f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      item->GetOriginalMimeType(),
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      item->GetStartTime(),
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      item->GetEndTime(),
135ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      item->GetETag(),
136ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      item->GetLastModifiedTime(),
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      item->GetReceivedBytes(),
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      item->GetTotalBytes(),
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      item->GetState(),
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      item->GetDangerType(),
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      item->GetLastReason(),
1427dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      item->GetId(),
143a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      item->GetOpened(),
144a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      by_ext_id,
145a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      by_ext_name);
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool ShouldUpdateHistory(const history::DownloadRow* previous,
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                         const history::DownloadRow& current) {
150f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Ignore url, referrer, mime_type, original_mime_type, start_time,
151f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // id, db_handle, which don't change.
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return ((previous == NULL) ||
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          (previous->current_path != current.current_path) ||
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          (previous->target_path != current.target_path) ||
1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          (previous->end_time != current.end_time) ||
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          (previous->received_bytes != current.received_bytes) ||
1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          (previous->total_bytes != current.total_bytes) ||
158ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch          (previous->etag != current.etag) ||
159ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch          (previous->last_modified != current.last_modified) ||
1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          (previous->state != current.state) ||
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          (previous->danger_type != current.danger_type) ||
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          (previous->interrupt_reason != current.interrupt_reason) ||
163a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)          (previous->opened != current.opened) ||
164a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)          (previous->by_ext_id != current.by_ext_id) ||
165a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)          (previous->by_ext_name != current.by_ext_name));
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)typedef std::vector<history::DownloadRow> InfoVector;
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // anonymous namespace
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)DownloadHistory::HistoryAdapter::HistoryAdapter(HistoryService* history)
1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  : history_(history) {
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)DownloadHistory::HistoryAdapter::~HistoryAdapter() {}
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DownloadHistory::HistoryAdapter::QueryDownloads(
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const HistoryService::DownloadQueryCallback& callback) {
1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  history_->QueryDownloads(callback);
1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DownloadHistory::HistoryAdapter::CreateDownload(
1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const history::DownloadRow& info,
1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const HistoryService::DownloadCreateCallback& callback) {
1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  history_->CreateDownload(info, callback);
1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DownloadHistory::HistoryAdapter::UpdateDownload(
1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const history::DownloadRow& data) {
1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  history_->UpdateDownload(data);
1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DownloadHistory::HistoryAdapter::RemoveDownloads(
1947dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    const std::set<uint32>& ids) {
1957dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  history_->RemoveDownloads(ids);
1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)DownloadHistory::Observer::Observer() {}
1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)DownloadHistory::Observer::~Observer() {}
2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
201cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// static
202cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)bool DownloadHistory::IsPersisted(const content::DownloadItem* item) {
203cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  const DownloadHistoryData* data = DownloadHistoryData::Get(item);
2047dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  return data && (data->state() == DownloadHistoryData::PERSISTED);
2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
207c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)DownloadHistory::DownloadHistory(content::DownloadManager* manager,
208c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                 scoped_ptr<HistoryAdapter> history)
209c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  : notifier_(manager, this),
2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    history_(history.Pass()),
2117dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    loading_id_(content::DownloadItem::kInvalidId),
2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    history_size_(0),
213c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    weak_ptr_factory_(this) {
2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  content::DownloadManager::DownloadVector items;
2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  notifier_.GetManager()->GetAllDownloads(&items);
2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (content::DownloadManager::DownloadVector::const_iterator
2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       it = items.begin(); it != items.end(); ++it) {
2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    OnDownloadCreated(notifier_.GetManager(), *it);
2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  history_->QueryDownloads(base::Bind(
2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      &DownloadHistory::QueryCallback, weak_ptr_factory_.GetWeakPtr()));
2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)DownloadHistory::~DownloadHistory() {
2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  FOR_EACH_OBSERVER(Observer, observers_, OnDownloadHistoryDestroyed());
2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  observers_.Clear();
2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DownloadHistory::AddObserver(DownloadHistory::Observer* observer) {
2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  observers_.AddObserver(observer);
2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DownloadHistory::RemoveObserver(DownloadHistory::Observer* observer) {
2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  observers_.RemoveObserver(observer);
2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
241cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)bool DownloadHistory::WasRestoredFromHistory(
242cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const content::DownloadItem* download) const {
243cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
244cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  const DownloadHistoryData* data = DownloadHistoryData::Get(download);
245cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
246cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // The OnDownloadCreated handler sets the was_restored_from_history flag when
247cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // resetting the loading_id_. So one of the two conditions below will hold for
248cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // a download restored from history even if the caller of this method is
249cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // racing with our OnDownloadCreated handler.
250cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return (data && data->was_restored_from_history()) ||
251cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)         download->GetId() == loading_id_;
252cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
253cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DownloadHistory::QueryCallback(scoped_ptr<InfoVector> infos) {
2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // ManagerGoingDown() may have happened before the history loaded.
2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!notifier_.GetManager())
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (InfoVector::const_iterator it = infos->begin();
2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       it != infos->end(); ++it) {
2617dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    loading_id_ = it->id;
2627dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    content::DownloadItem* item = notifier_.GetManager()->CreateDownloadItem(
2637dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        loading_id_,
2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        it->current_path,
2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        it->target_path,
2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        it->url_chain,
2672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        it->referrer_url,
268f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        it->mime_type,
269f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        it->original_mime_type,
2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        it->start_time,
2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        it->end_time,
272ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        it->etag,
273ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        it->last_modified,
2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        it->received_bytes,
2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        it->total_bytes,
2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        it->state,
2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        it->danger_type,
2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        it->interrupt_reason,
2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        it->opened);
28046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#if defined(ENABLE_EXTENSIONS)
281a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    if (!it->by_ext_id.empty() && !it->by_ext_name.empty()) {
2825c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      new extensions::DownloadedByExtension(
2835c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu          item, it->by_ext_id, it->by_ext_name);
284a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      item->UpdateObservers();
285a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    }
286a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#endif
287cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    DCHECK_EQ(DownloadHistoryData::PERSISTED,
288cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)              DownloadHistoryData::Get(item)->state());
2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ++history_size_;
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  notifier_.GetManager()->CheckForHistoryFilesRemoval();
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DownloadHistory::MaybeAddToHistory(content::DownloadItem* item) {
2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2977dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  uint32 download_id = item->GetId();
2982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DownloadHistoryData* data = DownloadHistoryData::Get(item);
2997dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  bool removing = removing_ids_.find(download_id) != removing_ids_.end();
3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // TODO(benjhayden): Remove IsTemporary().
3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (download_crx_util::IsExtensionDownload(*item) ||
3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      item->IsTemporary() ||
3047dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      (data->state() != DownloadHistoryData::NOT_PERSISTED) ||
3052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      removing)
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3087dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  data->SetState(DownloadHistoryData::PERSISTING);
3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (data->info() == NULL) {
3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Keep the info here regardless of whether the item is in progress so that,
3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // when ItemAdded() calls OnDownloadUpdated(), it can decide whether to
3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Update the db and/or clear the info.
3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    data->set_info(GetDownloadRow(item));
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  history_->CreateDownload(*data->info(), base::Bind(
3172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      &DownloadHistory::ItemAdded, weak_ptr_factory_.GetWeakPtr(),
3182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      download_id));
3197dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  FOR_EACH_OBSERVER(Observer, observers_, OnDownloadStored(
3207dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      item, *data->info()));
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3237dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid DownloadHistory::ItemAdded(uint32 download_id, bool success) {
3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (removed_while_adding_.find(download_id) !=
3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      removed_while_adding_.end()) {
3262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    removed_while_adding_.erase(download_id);
3277dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    if (success)
3287dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      ScheduleRemoveDownload(download_id);
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!notifier_.GetManager())
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  content::DownloadItem* item = notifier_.GetManager()->GetDownload(
3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      download_id);
3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!item) {
3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // This item will have called OnDownloadDestroyed().  If the item should
3392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // have been removed from history, then it would have also called
3402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // OnDownloadRemoved(), which would have put |download_id| in
3412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // removed_while_adding_, handled above.
3422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
3432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DownloadHistoryData* data = DownloadHistoryData::Get(item);
3462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // The sql INSERT statement failed. Avoid an infinite loop: don't
3482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // automatically retry. Retry adding the next time the item is updated by
3497dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // resetting the state to NOT_PERSISTED.
3507dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!success) {
3512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DVLOG(20) << __FUNCTION__ << " INSERT failed id=" << download_id;
3527dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    data->SetState(DownloadHistoryData::NOT_PERSISTED);
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3557dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  data->SetState(DownloadHistoryData::PERSISTED);
3562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  UMA_HISTOGRAM_CUSTOM_COUNTS("Download.HistorySize2",
3582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                              history_size_,
3592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                              0/*min*/,
3602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                              (1 << 23)/*max*/,
3612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                              (1 << 7)/*num_buckets*/);
3622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ++history_size_;
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // In case the item changed or became temporary while it was being added.
3652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Don't just update all of the item's observers because we're the only
3667dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // observer that can also see data->state(), which is the only thing that
3677dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // ItemAdded() changed.
3682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  OnDownloadUpdated(notifier_.GetManager(), item);
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DownloadHistory::OnDownloadCreated(
3722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    content::DownloadManager* manager, content::DownloadItem* item) {
3732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
3742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // All downloads should pass through OnDownloadCreated exactly once.
3762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CHECK(!DownloadHistoryData::Get(item));
3777dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DownloadHistoryData* data = new DownloadHistoryData(item);
3787dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (item->GetId() == loading_id_) {
3797dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    data->SetState(DownloadHistoryData::PERSISTED);
380cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    data->set_was_restored_from_history(true);
3817dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    loading_id_ = content::DownloadItem::kInvalidId;
3827dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
3832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (item->GetState() == content::DownloadItem::IN_PROGRESS) {
3842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    data->set_info(GetDownloadRow(item));
3852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  MaybeAddToHistory(item);
3872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DownloadHistory::OnDownloadUpdated(
3902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    content::DownloadManager* manager, content::DownloadItem* item) {
3912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
3922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DownloadHistoryData* data = DownloadHistoryData::Get(item);
3947dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (data->state() == DownloadHistoryData::NOT_PERSISTED) {
3952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    MaybeAddToHistory(item);
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (item->IsTemporary()) {
3992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    OnDownloadRemoved(notifier_.GetManager(), item);
4002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
4012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  history::DownloadRow current_info(GetDownloadRow(item));
4042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool should_update = ShouldUpdateHistory(data->info(), current_info);
4052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  UMA_HISTOGRAM_ENUMERATION("Download.HistoryPropagatedUpdate",
4062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            should_update, 2);
4072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (should_update) {
4082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    history_->UpdateDownload(current_info);
4092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    FOR_EACH_OBSERVER(Observer, observers_, OnDownloadStored(
4102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        item, current_info));
4112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (item->GetState() == content::DownloadItem::IN_PROGRESS) {
4132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    data->set_info(current_info);
4142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
4152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    data->clear_info();
4162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DownloadHistory::OnDownloadOpened(
4202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    content::DownloadManager* manager, content::DownloadItem* item) {
4212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  OnDownloadUpdated(manager, item);
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DownloadHistory::OnDownloadRemoved(
4252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    content::DownloadManager* manager, content::DownloadItem* item) {
4262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
4272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DownloadHistoryData* data = DownloadHistoryData::Get(item);
4297dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (data->state() != DownloadHistoryData::PERSISTED) {
4307dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    if (data->state() == DownloadHistoryData::PERSISTING) {
4312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // ScheduleRemoveDownload will be called when history_ calls ItemAdded().
4322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      removed_while_adding_.insert(item->GetId());
4332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
4342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
4352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4367dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  ScheduleRemoveDownload(item->GetId());
4377dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // This is important: another OnDownloadRemoved() handler could do something
4387dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // that synchronously fires an OnDownloadUpdated().
4397dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  data->SetState(DownloadHistoryData::NOT_PERSISTED);
4402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // ItemAdded increments history_size_ only if the item wasn't
4412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // removed_while_adding_, so the next line does not belong in
4422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // ScheduleRemoveDownload().
4432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  --history_size_;
4442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4467dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid DownloadHistory::ScheduleRemoveDownload(uint32 download_id) {
4472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
4482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // For database efficiency, batch removals together if they happen all at
4502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // once.
4517dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (removing_ids_.empty()) {
4522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
4532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(&DownloadHistory::RemoveDownloadsBatch,
4542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   weak_ptr_factory_.GetWeakPtr()));
4552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  removing_ids_.insert(download_id);
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DownloadHistory::RemoveDownloadsBatch() {
4602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
4612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  IdSet remove_ids;
4622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  removing_ids_.swap(remove_ids);
4637dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  history_->RemoveDownloads(remove_ids);
4642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  FOR_EACH_OBSERVER(Observer, observers_, OnDownloadsRemoved(remove_ids));
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
466