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 #ifndef CHROME_BROWSER_DOWNLOAD_DOWNLOAD_HISTORY_H_
6 #define CHROME_BROWSER_DOWNLOAD_DOWNLOAD_HISTORY_H_
7 
8 #include <stdint.h>
9 
10 #include <set>
11 #include <vector>
12 
13 #include "base/callback.h"
14 #include "base/macros.h"
15 #include "base/memory/weak_ptr.h"
16 #include "base/observer_list.h"
17 #include "components/download/content/public/all_download_item_notifier.h"
18 #include "components/download/public/common/download_item.h"
19 #include "components/history/core/browser/history_service.h"
20 #include "content/public/browser/download_manager.h"
21 
22 namespace history {
23 struct DownloadRow;
24 }  // namespace history
25 
26 // Observes a single DownloadManager and all its DownloadItems, keeping the
27 // DownloadDatabase up to date.
28 class DownloadHistory : public download::AllDownloadItemNotifier::Observer {
29  public:
30   typedef std::set<uint32_t> IdSet;
31 
32   // Caller must guarantee that HistoryService outlives HistoryAdapter.
33   class HistoryAdapter {
34    public:
35     explicit HistoryAdapter(history::HistoryService* history);
36     virtual ~HistoryAdapter();
37 
38     virtual void QueryDownloads(
39         history::HistoryService::DownloadQueryCallback callback);
40 
41     virtual void CreateDownload(
42         const history::DownloadRow& info,
43         history::HistoryService::DownloadCreateCallback callback);
44 
45     virtual void UpdateDownload(const history::DownloadRow& data,
46                                 bool should_commit_immediately);
47 
48     virtual void RemoveDownloads(const std::set<uint32_t>& ids);
49 
50    private:
51     history::HistoryService* history_;
52     DISALLOW_COPY_AND_ASSIGN(HistoryAdapter);
53   };
54 
55   class Observer {
56    public:
57     Observer();
58     virtual ~Observer();
59 
60     // Fires when a download is added to or updated in the database, just after
61     // the task is posted to the history thread.
OnDownloadStored(download::DownloadItem * item,const history::DownloadRow & info)62     virtual void OnDownloadStored(download::DownloadItem* item,
63                                   const history::DownloadRow& info) {}
64 
65     // Fires when RemoveDownloads messages are sent to the DB thread.
OnDownloadsRemoved(const IdSet & ids)66     virtual void OnDownloadsRemoved(const IdSet& ids) {}
67 
68     // Fires when the DownloadHistory completes the initial history query.
69     // Unlike the other observer methods, this one is invoked if the initial
70     // history query has already completed by the time the caller calls
71     // AddObserver().
OnHistoryQueryComplete()72     virtual void OnHistoryQueryComplete() {}
73 
74     // Fires when the DownloadHistory is being destroyed so that implementors
75     // can RemoveObserver() and nullify their DownloadHistory*s.
OnDownloadHistoryDestroyed()76     virtual void OnDownloadHistoryDestroyed() {}
77   };
78 
79   // Returns true if the download is persisted. Not reliable when called from
80   // within a DownloadManager::Observer::OnDownloadCreated handler since the
81   // persisted state may not yet have been updated for a download that was
82   // restored from history.
83   static bool IsPersisted(const download::DownloadItem* item);
84 
85   // Neither |manager| nor |history| may be NULL.
86   // DownloadService creates DownloadHistory some time after DownloadManager is
87   // created and destroys DownloadHistory as DownloadManager is shutting down.
88   DownloadHistory(content::DownloadManager* manager,
89                   std::unique_ptr<HistoryAdapter> history);
90 
91   ~DownloadHistory() override;
92 
93   void AddObserver(Observer* observer);
94   void RemoveObserver(Observer* observer);
95 
96  private:
97   // Callback from |history_| containing all entries in the downloads database
98   // table.
99   void QueryCallback(std::vector<history::DownloadRow> rows);
100 
101   // Called to create all history downloads.
102   void LoadHistoryDownloads(std::vector<history::DownloadRow> rows);
103 
104   // May add |item| to |history_|.
105   void MaybeAddToHistory(download::DownloadItem* item);
106 
107   // Callback from |history_| when an item was successfully inserted into the
108   // database.
109   void ItemAdded(uint32_t id, const history::DownloadRow& info, bool success);
110 
111   // AllDownloadItemNotifier::Observer
112   void OnDownloadCreated(content::DownloadManager* manager,
113                          download::DownloadItem* item) override;
114   void OnDownloadUpdated(content::DownloadManager* manager,
115                          download::DownloadItem* item) override;
116   void OnDownloadOpened(content::DownloadManager* manager,
117                         download::DownloadItem* item) override;
118   void OnDownloadRemoved(content::DownloadManager* manager,
119                          download::DownloadItem* item) override;
120 
121   // Schedule a record to be removed from |history_| the next time
122   // RemoveDownloadsBatch() runs. Schedule RemoveDownloadsBatch() to be run soon
123   // if it isn't already scheduled.
124   void ScheduleRemoveDownload(uint32_t download_id);
125 
126   // Removes all |removing_ids_| from |history_|.
127   void RemoveDownloadsBatch();
128 
129   // Called when a download was restored from history.
130   void OnDownloadRestoredFromHistory(download::DownloadItem* item);
131 
132   // Check whether an download item needs be updated or added to history DB.
133   bool NeedToUpdateDownloadHistory(download::DownloadItem* item);
134 
135   download::AllDownloadItemNotifier notifier_;
136 
137   std::unique_ptr<HistoryAdapter> history_;
138 
139   // Identifier of the item being created in QueryCallback(), matched up with
140   // created items in OnDownloadCreated() so that the item is not re-added to
141   // the database.
142   uint32_t loading_id_;
143 
144   // Identifiers of items that are scheduled for removal from history, to
145   // facilitate batching removals together for database efficiency.
146   IdSet removing_ids_;
147 
148   // |GetId()|s of items that were removed while they were being added, so that
149   // they can be removed when the database finishes adding them.
150   // TODO(benjhayden) Can this be removed now that it doesn't need to wait for
151   // the db_handle, and can rely on PostTask sequentiality?
152   IdSet removed_while_adding_;
153 
154   bool initial_history_query_complete_;
155 
156   base::ObserverList<Observer>::Unchecked observers_;
157 
158   base::WeakPtrFactory<DownloadHistory> weak_ptr_factory_{this};
159 
160   DISALLOW_COPY_AND_ASSIGN(DownloadHistory);
161 };
162 
163 #endif  // CHROME_BROWSER_DOWNLOAD_DOWNLOAD_HISTORY_H_
164