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.
5 #include "chrome/browser/browsing_data/browsing_data_file_system_helper.h"
8 #include "base/compiler_specific.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/message_loop/message_loop.h"
11 #include "base/sequenced_task_runner.h"
12 #include "base/strings/string_util.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "chrome/browser/browsing_data/browsing_data_helper.h"
15 #include "content/public/browser/browser_thread.h"
16 #include "webkit/browser/fileapi/file_system_context.h"
17 #include "webkit/browser/fileapi/file_system_quota_util.h"
18 #include "webkit/common/fileapi/file_system_types.h"
20 using content::BrowserThread;
23 class FileSystemContext;
28 // An implementation of the BrowsingDataFileSystemHelper interface that pulls
29 // data from a given |filesystem_context| and returns a list of FileSystemInfo
31 class BrowsingDataFileSystemHelperImpl : public BrowsingDataFileSystemHelper {
33 // BrowsingDataFileSystemHelper implementation
34 explicit BrowsingDataFileSystemHelperImpl(
35 fileapi::FileSystemContext* filesystem_context);
36 virtual void StartFetching(const base::Callback<
37 void(const std::list<FileSystemInfo>&)>& callback) OVERRIDE;
38 virtual void DeleteFileSystemOrigin(const GURL& origin) OVERRIDE;
41 virtual ~BrowsingDataFileSystemHelperImpl();
43 // Enumerates all filesystem files, storing the resulting list into
44 // file_system_file_ for later use. This must be called on the file
46 void FetchFileSystemInfoInFileThread();
48 // Triggers the success callback as the end of a StartFetching workflow. This
49 // must be called on the UI thread.
50 void NotifyOnUIThread();
52 // Deletes all file systems associated with |origin|. This must be called on
53 // the file task runner.
54 void DeleteFileSystemOriginInFileThread(const GURL& origin);
56 // Returns the file task runner for the |filesystem_context_|.
57 base::SequencedTaskRunner* file_task_runner() {
58 return filesystem_context_->default_file_task_runner();
61 // Keep a reference to the FileSystemContext object for the current profile
62 // for use on the file task runner.
63 scoped_refptr<fileapi::FileSystemContext> filesystem_context_;
65 // Holds the current list of file systems returned to the client after
66 // StartFetching is called. Access to |file_system_info_| is triggered
67 // indirectly via the UI thread and guarded by |is_fetching_|. This means
68 // |file_system_info_| is only accessed while |is_fetching_| is true. The
69 // flag |is_fetching_| is only accessed on the UI thread. In the context of
70 // this class |file_system_info_| only mutates on the file task runner.
71 std::list<FileSystemInfo> file_system_info_;
73 // Holds the callback passed in at the beginning of the StartFetching workflow
74 // so that it can be triggered via NotifyOnUIThread. This only mutates on the
76 base::Callback<void(const std::list<FileSystemInfo>&)> completion_callback_;
78 // Indicates whether or not we're currently fetching information: set to true
79 // when StartFetching is called on the UI thread, and reset to false when
80 // NotifyOnUIThread triggers the success callback.
81 // This property only mutates on the UI thread.
84 DISALLOW_COPY_AND_ASSIGN(BrowsingDataFileSystemHelperImpl);
87 BrowsingDataFileSystemHelperImpl::BrowsingDataFileSystemHelperImpl(
88 fileapi::FileSystemContext* filesystem_context)
89 : filesystem_context_(filesystem_context),
91 DCHECK(filesystem_context_.get());
94 BrowsingDataFileSystemHelperImpl::~BrowsingDataFileSystemHelperImpl() {
97 void BrowsingDataFileSystemHelperImpl::StartFetching(
98 const base::Callback<void(const std::list<FileSystemInfo>&)>& callback) {
99 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
100 DCHECK(!is_fetching_);
101 DCHECK_EQ(false, callback.is_null());
103 completion_callback_ = callback;
104 file_task_runner()->PostTask(
107 &BrowsingDataFileSystemHelperImpl::FetchFileSystemInfoInFileThread,
111 void BrowsingDataFileSystemHelperImpl::DeleteFileSystemOrigin(
112 const GURL& origin) {
113 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
114 file_task_runner()->PostTask(
117 &BrowsingDataFileSystemHelperImpl::DeleteFileSystemOriginInFileThread,
121 void BrowsingDataFileSystemHelperImpl::FetchFileSystemInfoInFileThread() {
122 DCHECK(file_task_runner()->RunsTasksOnCurrentThread());
124 // We check usage for these filesystem types.
125 const fileapi::FileSystemType types[] = {
126 fileapi::kFileSystemTypeTemporary,
127 fileapi::kFileSystemTypePersistent,
128 fileapi::kFileSystemTypeSyncable,
131 typedef std::map<GURL, FileSystemInfo> OriginInfoMap;
132 OriginInfoMap file_system_info_map;
133 for (size_t i = 0; i < arraysize(types); ++i) {
134 fileapi::FileSystemType type = types[i];
135 fileapi::FileSystemQuotaUtil* quota_util =
136 filesystem_context_->GetQuotaUtil(type);
138 std::set<GURL> origins;
139 quota_util->GetOriginsForTypeOnFileThread(type, &origins);
140 for (std::set<GURL>::iterator iter = origins.begin();
141 iter != origins.end(); ++iter) {
142 const GURL& current = *iter;
143 if (!BrowsingDataHelper::HasWebScheme(current))
144 continue; // Non-websafe state is not considered browsing data.
145 int64 usage = quota_util->GetOriginUsageOnFileThread(
146 filesystem_context_.get(), current, type);
147 OriginInfoMap::iterator inserted =
148 file_system_info_map.insert(
149 std::make_pair(current, FileSystemInfo(current))).first;
150 inserted->second.usage_map[type] = usage;
154 for (OriginInfoMap::iterator iter = file_system_info_map.begin();
155 iter != file_system_info_map.end(); ++iter) {
156 file_system_info_.push_back(iter->second);
159 BrowserThread::PostTask(
160 BrowserThread::UI, FROM_HERE,
161 base::Bind(&BrowsingDataFileSystemHelperImpl::NotifyOnUIThread, this));
164 void BrowsingDataFileSystemHelperImpl::NotifyOnUIThread() {
165 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
166 DCHECK(is_fetching_);
167 completion_callback_.Run(file_system_info_);
168 completion_callback_.Reset();
169 is_fetching_ = false;
172 void BrowsingDataFileSystemHelperImpl::DeleteFileSystemOriginInFileThread(
173 const GURL& origin) {
174 DCHECK(file_task_runner()->RunsTasksOnCurrentThread());
175 filesystem_context_->DeleteDataForOriginOnFileThread(origin);
180 BrowsingDataFileSystemHelper::FileSystemInfo::FileSystemInfo(
181 const GURL& origin) : origin(origin) {}
183 BrowsingDataFileSystemHelper::FileSystemInfo::~FileSystemInfo() {}
186 BrowsingDataFileSystemHelper* BrowsingDataFileSystemHelper::Create(
187 fileapi::FileSystemContext* filesystem_context) {
188 return new BrowsingDataFileSystemHelperImpl(filesystem_context);
191 CannedBrowsingDataFileSystemHelper::CannedBrowsingDataFileSystemHelper(
193 : is_fetching_(false) {
196 CannedBrowsingDataFileSystemHelper::CannedBrowsingDataFileSystemHelper()
197 : is_fetching_(false) {
200 CannedBrowsingDataFileSystemHelper::~CannedBrowsingDataFileSystemHelper() {}
202 CannedBrowsingDataFileSystemHelper*
203 CannedBrowsingDataFileSystemHelper::Clone() {
204 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
205 CannedBrowsingDataFileSystemHelper* clone =
206 new CannedBrowsingDataFileSystemHelper();
207 // This list only mutates on the UI thread, so it's safe to work with it here
208 // (given the DCHECK above).
209 clone->file_system_info_ = file_system_info_;
213 void CannedBrowsingDataFileSystemHelper::AddFileSystem(
214 const GURL& origin, const fileapi::FileSystemType type, const int64 size) {
215 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
216 // This canned implementation of AddFileSystem uses an O(n^2) algorithm; which
217 // is fine, as it isn't meant for use in a high-volume context. If it turns
218 // out that we want to start using this in a context with many, many origins,
219 // we should think about reworking the implementation.
220 bool duplicate_origin = false;
221 for (std::list<FileSystemInfo>::iterator
222 file_system = file_system_info_.begin();
223 file_system != file_system_info_.end();
225 if (file_system->origin == origin) {
226 file_system->usage_map[type] = size;
227 duplicate_origin = true;
231 if (duplicate_origin)
234 if (!BrowsingDataHelper::HasWebScheme(origin))
235 return; // Non-websafe state is not considered browsing data.
237 FileSystemInfo info(origin);
238 info.usage_map[type] = size;
239 file_system_info_.push_back(info);
242 void CannedBrowsingDataFileSystemHelper::Reset() {
243 file_system_info_.clear();
246 bool CannedBrowsingDataFileSystemHelper::empty() const {
247 return file_system_info_.empty();
250 size_t CannedBrowsingDataFileSystemHelper::GetFileSystemCount() const {
251 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
252 return file_system_info_.size();
255 void CannedBrowsingDataFileSystemHelper::StartFetching(
256 const base::Callback<void(const std::list<FileSystemInfo>&)>& callback) {
257 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
258 DCHECK(!is_fetching_);
259 DCHECK_EQ(false, callback.is_null());
261 completion_callback_ = callback;
263 BrowserThread::PostTask(
264 BrowserThread::UI, FROM_HERE,
265 base::Bind(&CannedBrowsingDataFileSystemHelper::NotifyOnUIThread, this));
268 void CannedBrowsingDataFileSystemHelper::NotifyOnUIThread() {
269 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
270 DCHECK(is_fetching_);
271 completion_callback_.Run(file_system_info_);
272 completion_callback_.Reset();
273 is_fetching_ = false;