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 "storage/browser/fileapi/sandbox_quota_observer.h"
6
7#include "base/sequenced_task_runner.h"
8#include "storage/browser/fileapi/file_system_url.h"
9#include "storage/browser/fileapi/file_system_usage_cache.h"
10#include "storage/browser/fileapi/sandbox_file_system_backend_delegate.h"
11#include "storage/browser/fileapi/timed_task_helper.h"
12#include "storage/browser/quota/quota_client.h"
13#include "storage/browser/quota/quota_manager_proxy.h"
14#include "storage/common/fileapi/file_system_util.h"
15
16namespace storage {
17
18SandboxQuotaObserver::SandboxQuotaObserver(
19    storage::QuotaManagerProxy* quota_manager_proxy,
20    base::SequencedTaskRunner* update_notify_runner,
21    ObfuscatedFileUtil* sandbox_file_util,
22    FileSystemUsageCache* file_system_usage_cache)
23    : quota_manager_proxy_(quota_manager_proxy),
24      update_notify_runner_(update_notify_runner),
25      sandbox_file_util_(sandbox_file_util),
26      file_system_usage_cache_(file_system_usage_cache) {
27}
28
29SandboxQuotaObserver::~SandboxQuotaObserver() {}
30
31void SandboxQuotaObserver::OnStartUpdate(const FileSystemURL& url) {
32  DCHECK(update_notify_runner_->RunsTasksOnCurrentThread());
33  base::FilePath usage_file_path = GetUsageCachePath(url);
34  if (usage_file_path.empty())
35    return;
36  file_system_usage_cache_->IncrementDirty(usage_file_path);
37}
38
39void SandboxQuotaObserver::OnUpdate(const FileSystemURL& url,
40                                    int64 delta) {
41  DCHECK(update_notify_runner_->RunsTasksOnCurrentThread());
42
43  if (quota_manager_proxy_.get()) {
44    quota_manager_proxy_->NotifyStorageModified(
45        storage::QuotaClient::kFileSystem,
46        url.origin(),
47        FileSystemTypeToQuotaStorageType(url.type()),
48        delta);
49  }
50
51  base::FilePath usage_file_path = GetUsageCachePath(url);
52  if (usage_file_path.empty())
53    return;
54
55  pending_update_notification_[usage_file_path] += delta;
56  if (!delayed_cache_update_helper_) {
57    delayed_cache_update_helper_.reset(
58        new TimedTaskHelper(update_notify_runner_.get()));
59    delayed_cache_update_helper_->Start(
60        FROM_HERE,
61        base::TimeDelta(),  // No delay.
62        base::Bind(&SandboxQuotaObserver::ApplyPendingUsageUpdate,
63                   base::Unretained(this)));
64  }
65}
66
67void SandboxQuotaObserver::OnEndUpdate(const FileSystemURL& url) {
68  DCHECK(update_notify_runner_->RunsTasksOnCurrentThread());
69
70  base::FilePath usage_file_path = GetUsageCachePath(url);
71  if (usage_file_path.empty())
72    return;
73
74  PendingUpdateNotificationMap::iterator found =
75      pending_update_notification_.find(usage_file_path);
76  if (found != pending_update_notification_.end()) {
77    UpdateUsageCacheFile(found->first, found->second);
78    pending_update_notification_.erase(found);
79  }
80
81  file_system_usage_cache_->DecrementDirty(usage_file_path);
82}
83
84void SandboxQuotaObserver::OnAccess(const FileSystemURL& url) {
85  if (quota_manager_proxy_.get()) {
86    quota_manager_proxy_->NotifyStorageAccessed(
87        storage::QuotaClient::kFileSystem,
88        url.origin(),
89        FileSystemTypeToQuotaStorageType(url.type()));
90  }
91}
92
93void SandboxQuotaObserver::SetUsageCacheEnabled(
94    const GURL& origin,
95    FileSystemType type,
96    bool enabled) {
97  if (quota_manager_proxy_.get()) {
98    quota_manager_proxy_->SetUsageCacheEnabled(
99        storage::QuotaClient::kFileSystem,
100        origin,
101        FileSystemTypeToQuotaStorageType(type),
102        enabled);
103  }
104}
105
106base::FilePath SandboxQuotaObserver::GetUsageCachePath(
107    const FileSystemURL& url) {
108  DCHECK(sandbox_file_util_);
109  base::File::Error error = base::File::FILE_OK;
110  base::FilePath path =
111      SandboxFileSystemBackendDelegate::GetUsageCachePathForOriginAndType(
112          sandbox_file_util_, url.origin(), url.type(), &error);
113  if (error != base::File::FILE_OK) {
114    LOG(WARNING) << "Could not get usage cache path for: "
115                 << url.DebugString();
116    return base::FilePath();
117  }
118  return path;
119}
120
121void SandboxQuotaObserver::ApplyPendingUsageUpdate() {
122  delayed_cache_update_helper_.reset();
123  for (PendingUpdateNotificationMap::iterator itr =
124           pending_update_notification_.begin();
125       itr != pending_update_notification_.end();
126       ++itr) {
127    UpdateUsageCacheFile(itr->first, itr->second);
128  }
129  pending_update_notification_.clear();
130}
131
132void SandboxQuotaObserver::UpdateUsageCacheFile(
133    const base::FilePath& usage_file_path,
134    int64 delta) {
135  DCHECK(!usage_file_path.empty());
136  if (!usage_file_path.empty() && delta != 0)
137    file_system_usage_cache_->AtomicUpdateUsageByDelta(usage_file_path, delta);
138}
139
140}  // namespace storage
141