1// Copyright 2014 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_EXTENSIONS_UPDATER_LOCAL_EXTENSION_CACHE_H_
6#define CHROME_BROWSER_EXTENSIONS_UPDATER_LOCAL_EXTENSION_CACHE_H_
7
8#include <map>
9#include <string>
10
11#include "base/callback_forward.h"
12#include "base/files/file_path.h"
13#include "base/memory/scoped_ptr.h"
14#include "base/memory/weak_ptr.h"
15#include "base/time/time.h"
16
17namespace extensions {
18
19// Cache .crx files in some local dir for future use. Cache keeps only latest
20// version of the extensions. Only one instance of LocalExtensionCache can work
21// with the same directory. But LocalExtensionCache instance can be shared
22// between multiple clients. Public interface can be used only from UI thread.
23class LocalExtensionCache {
24 public:
25  // Callback invoked on UI thread when PutExtension is completed.
26  typedef base::Callback<void(const base::FilePath& file_path,
27                              bool file_ownership_passed)> PutExtensionCallback;
28
29  // |cache_dir| - directory that will be used for caching CRX files.
30  // |max_cache_size| - maximum disk space that cache can use, 0 means no limit.
31  // |max_cache_age| - maximum age that unused item can be kept in cache, 0 age
32  // means that all unused cache items will be removed on Shutdown.
33  // All file I/O is done via the |backend_task_runner|.
34  LocalExtensionCache(const base::FilePath& cache_dir,
35                      uint64 max_cache_size,
36                      const base::TimeDelta& max_cache_age,
37                      const scoped_refptr<base::SequencedTaskRunner>&
38                          backend_task_runner);
39  ~LocalExtensionCache();
40
41  // Name of flag file that indicates that cache is ready (import finished).
42  static const char kCacheReadyFlagFileName[];
43
44  // Initialize cache. If |wait_for_cache_initialization| is |true|, the cache
45  // contents will not be read until a flag file appears in the cache directory,
46  // signaling that the cache is ready. The |callback| is called when cache is
47  // ready and cache dir content was already checked.
48  void Init(bool wait_for_cache_initialization,
49            const base::Closure& callback);
50
51  // Shut down the cache. The |callback| will be invoked when the cache has shut
52  // down completely and there are no more pending file I/O operations.
53  void Shutdown(const base::Closure& callback);
54
55  // If extension with |id| exists in the cache, returns |true|, |file_path| and
56  // |version| for the extension. Extension will be marked as used with current
57  // timestamp.
58  bool GetExtension(const std::string& id,
59                    base::FilePath* file_path,
60                    std::string* version);
61
62  // Put extension with |id| and |version| into local cache. Older version in
63  // the cache will be on next run so it can be safely used. Extension will be
64  // marked as used with current timestamp. The file will be available via
65  // GetExtension when |callback| is called. PutExtension may get ownership
66  // of |file_path| or return it back via |callback|.
67  void PutExtension(const std::string& id,
68                    const base::FilePath& file_path,
69                    const std::string& version,
70                    const PutExtensionCallback& callback);
71
72  // Remove extension with |id| from local cache, corresponding crx file will be
73  // removed from disk too.
74  bool RemoveExtension(const std::string& id);
75
76  // Return cache statistics. Returns |false| if cache is not ready.
77  bool GetStatistics(uint64* cache_size,
78                     size_t* extensions_count);
79
80  bool is_ready() const { return state_ == kReady; }
81  bool is_uninitialized() const { return state_ == kUninitialized; }
82  bool is_shutdown() const { return state_ == kShutdown; }
83
84  // For tests only!
85  void SetCacheStatusPollingDelayForTests(const base::TimeDelta& delay);
86
87 private:
88  struct CacheItemInfo {
89    std::string version;
90    base::Time last_used;
91    uint64 size;
92    base::FilePath file_path;
93
94    CacheItemInfo(const std::string& version,
95                  const base::Time& last_used,
96                  uint64 size,
97                  const base::FilePath& file_path);
98  };
99  typedef std::map<std::string, CacheItemInfo> CacheMap;
100
101  enum State {
102    kUninitialized,
103    kWaitInitialization,
104    kReady,
105    kShutdown
106  };
107
108  // Sends BackendCheckCacheStatus task on backend thread.
109  void CheckCacheStatus(const base::Closure& callback);
110
111  // Checks whether a flag file exists in the |cache_dir|, indicating that the
112  // cache is ready. This method is invoked via the |backend_task_runner_| and
113  // posts its result back to the |local_cache| on the UI thread.
114  static void BackendCheckCacheStatus(
115      base::WeakPtr<LocalExtensionCache> local_cache,
116      const base::FilePath& cache_dir,
117      const base::Closure& callback);
118
119  // Invoked on the UI thread after checking whether the cache is ready. If the
120  // cache is not ready yet, posts a delayed task that will repeat the check,
121  // thus polling for cache readiness.
122  void OnCacheStatusChecked(bool ready, const base::Closure& callback);
123
124  // Checks the cache contents. This is a helper that invokes the actual check
125  // by posting to the |backend_task_runner_|.
126  void CheckCacheContents(const base::Closure& callback);
127
128  // Checks the cache contents. This method is invoked via the
129  // |backend_task_runner_| and posts back a list of cache entries to the
130  // |local_cache| on the UI thread.
131  static void BackendCheckCacheContents(
132      base::WeakPtr<LocalExtensionCache> local_cache,
133      const base::FilePath& cache_dir,
134      const base::Closure& callback);
135
136  // Helper for BackendCheckCacheContents() that updates |cache_content|.
137  static void BackendCheckCacheContentsInternal(
138      const base::FilePath& cache_dir,
139      CacheMap* cache_content);
140
141  // Invoked when the cache content on disk has been checked. |cache_content|
142  // contains all the currently valid crx files in the cache.
143  void OnCacheContentsChecked(scoped_ptr<CacheMap> cache_content,
144                              const base::Closure& callback);
145
146  // Update timestamp for the file to mark it as "used". This method is invoked
147  // via the |backend_task_runner_|.
148  static void BackendMarkFileUsed(const base::FilePath& file_path,
149                                  const base::Time& time);
150
151  // Installs the downloaded crx file at |path| in the |cache_dir|. This method
152  // is invoked via the |backend_task_runner_|.
153  static void BackendInstallCacheEntry(
154      base::WeakPtr<LocalExtensionCache> local_cache,
155      const base::FilePath& cache_dir,
156      const std::string& id,
157      const base::FilePath& file_path,
158      const std::string& version,
159      const PutExtensionCallback& callback);
160
161  // Invoked on the UI thread when a new entry has been installed in the cache.
162  void OnCacheEntryInstalled(const std::string& id,
163                             const CacheItemInfo& info,
164                             bool was_error,
165                             const PutExtensionCallback& callback);
166
167  // Remove cached crx files(all versions) under |cached_dir| for extension with
168  // |id|. This method is invoked via the |backend_task_runner_|.
169  static void BackendRemoveCacheEntry(const base::FilePath& cache_dir,
170                                      const std::string& id);
171
172  // Compare two cache items returns true if first item is older.
173  static bool CompareCacheItemsAge(const CacheMap::iterator& lhs,
174                                   const CacheMap::iterator& rhs);
175
176  // Calculate which files need to be deleted and schedule files deletion.
177  void CleanUp();
178
179  // Path to the directory where the extension cache is stored.
180  base::FilePath cache_dir_;
181
182  // Maximum size of cache dir on disk.
183  uint64 max_cache_size_;
184
185  // Minimal age of unused item in cache, items prior to this age will be
186  // deleted on shutdown.
187  base::Time min_cache_age_;
188
189  // Task runner for executing file I/O tasks.
190  scoped_refptr<base::SequencedTaskRunner> backend_task_runner_;
191
192  // Track state of the instance.
193  State state_;
194
195  // This contains info about all cached extensions.
196  CacheMap cached_extensions_;
197
198  // Weak factory for callbacks from the backend and delayed tasks.
199  base::WeakPtrFactory<LocalExtensionCache> weak_ptr_factory_;
200
201  // Delay between polling cache status.
202  base::TimeDelta cache_status_polling_delay_;
203
204  DISALLOW_COPY_AND_ASSIGN(LocalExtensionCache);
205};
206
207}  // namespace extensions
208
209#endif  // CHROME_BROWSER_EXTENSIONS_UPDATER_LOCAL_EXTENSION_CACHE_H_
210