• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2013 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 "ppapi/proxy/file_system_resource.h"
6 
7 #include "base/bind.h"
8 #include "base/stl_util.h"
9 #include "ipc/ipc_message.h"
10 #include "ppapi/c/pp_errors.h"
11 #include "ppapi/proxy/ppapi_messages.h"
12 #include "ppapi/shared_impl/file_growth.h"
13 #include "ppapi/shared_impl/tracked_callback.h"
14 #include "ppapi/thunk/enter.h"
15 #include "ppapi/thunk/ppb_file_io_api.h"
16 
17 using ppapi::thunk::EnterResourceNoLock;
18 using ppapi::thunk::PPB_FileIO_API;
19 using ppapi::thunk::PPB_FileSystem_API;
20 
21 namespace ppapi {
22 namespace proxy {
23 
QuotaRequest(int64_t amount_arg,const RequestQuotaCallback & callback_arg)24 FileSystemResource::QuotaRequest::QuotaRequest(
25     int64_t amount_arg,
26     const RequestQuotaCallback& callback_arg)
27     : amount(amount_arg),
28       callback(callback_arg) {
29 }
30 
~QuotaRequest()31 FileSystemResource::QuotaRequest::~QuotaRequest() {
32 }
33 
FileSystemResource(Connection connection,PP_Instance instance,PP_FileSystemType type)34 FileSystemResource::FileSystemResource(Connection connection,
35                                        PP_Instance instance,
36                                        PP_FileSystemType type)
37     : PluginResource(connection, instance),
38       type_(type),
39       called_open_(false),
40       callback_count_(0),
41       callback_result_(PP_OK),
42       reserved_quota_(0),
43       reserving_quota_(false) {
44   DCHECK(type_ != PP_FILESYSTEMTYPE_INVALID);
45   SendCreate(RENDERER, PpapiHostMsg_FileSystem_Create(type_));
46   SendCreate(BROWSER, PpapiHostMsg_FileSystem_Create(type_));
47 }
48 
FileSystemResource(Connection connection,PP_Instance instance,int pending_renderer_id,int pending_browser_id,PP_FileSystemType type)49 FileSystemResource::FileSystemResource(Connection connection,
50                                        PP_Instance instance,
51                                        int pending_renderer_id,
52                                        int pending_browser_id,
53                                        PP_FileSystemType type)
54     : PluginResource(connection, instance),
55       type_(type),
56       called_open_(true),
57       callback_count_(0),
58       callback_result_(PP_OK),
59       reserved_quota_(0),
60       reserving_quota_(false) {
61   DCHECK(type_ != PP_FILESYSTEMTYPE_INVALID);
62   AttachToPendingHost(RENDERER, pending_renderer_id);
63   AttachToPendingHost(BROWSER, pending_browser_id);
64 }
65 
~FileSystemResource()66 FileSystemResource::~FileSystemResource() {
67 }
68 
AsPPB_FileSystem_API()69 PPB_FileSystem_API* FileSystemResource::AsPPB_FileSystem_API() {
70   return this;
71 }
72 
Open(int64_t expected_size,scoped_refptr<TrackedCallback> callback)73 int32_t FileSystemResource::Open(int64_t expected_size,
74                                  scoped_refptr<TrackedCallback> callback) {
75   DCHECK(type_ != PP_FILESYSTEMTYPE_ISOLATED);
76   if (called_open_)
77     return PP_ERROR_FAILED;
78   called_open_ = true;
79 
80   Call<PpapiPluginMsg_FileSystem_OpenReply>(RENDERER,
81       PpapiHostMsg_FileSystem_Open(expected_size),
82       base::Bind(&FileSystemResource::OpenComplete,
83                  this,
84                  callback));
85   Call<PpapiPluginMsg_FileSystem_OpenReply>(BROWSER,
86       PpapiHostMsg_FileSystem_Open(expected_size),
87       base::Bind(&FileSystemResource::OpenComplete,
88                  this,
89                  callback));
90   return PP_OK_COMPLETIONPENDING;
91 }
92 
GetType()93 PP_FileSystemType FileSystemResource::GetType() {
94   return type_;
95 }
96 
OpenQuotaFile(PP_Resource file_io)97 void FileSystemResource::OpenQuotaFile(PP_Resource file_io) {
98   DCHECK(!ContainsKey(files_, file_io));
99   files_.insert(file_io);
100 }
101 
CloseQuotaFile(PP_Resource file_io)102 void FileSystemResource::CloseQuotaFile(PP_Resource file_io) {
103   DCHECK(ContainsKey(files_, file_io));
104   files_.erase(file_io);
105 }
106 
RequestQuota(int64_t amount,const RequestQuotaCallback & callback)107 int64_t FileSystemResource::RequestQuota(
108     int64_t amount,
109     const RequestQuotaCallback& callback) {
110   DCHECK(amount >= 0);
111   if (!reserving_quota_ && reserved_quota_ >= amount) {
112     reserved_quota_ -= amount;
113     return amount;
114   }
115 
116   // Queue up a pending quota request.
117   pending_quota_requests_.push(QuotaRequest(amount, callback));
118 
119   // Reserve more quota if we haven't already.
120   if (!reserving_quota_)
121     ReserveQuota(amount);
122 
123   return PP_OK_COMPLETIONPENDING;
124 }
125 
InitIsolatedFileSystem(const std::string & fsid,PP_IsolatedFileSystemType_Private type,const base::Callback<void (int32_t)> & callback)126 int32_t FileSystemResource::InitIsolatedFileSystem(
127     const std::string& fsid,
128     PP_IsolatedFileSystemType_Private type,
129     const base::Callback<void(int32_t)>& callback) {
130   // This call is mutually exclusive with Open() above, so we can reuse the
131   // called_open state.
132   DCHECK(type_ == PP_FILESYSTEMTYPE_ISOLATED);
133   if (called_open_)
134     return PP_ERROR_FAILED;
135   called_open_ = true;
136 
137   Call<PpapiPluginMsg_FileSystem_InitIsolatedFileSystemReply>(RENDERER,
138       PpapiHostMsg_FileSystem_InitIsolatedFileSystem(fsid, type),
139       base::Bind(&FileSystemResource::InitIsolatedFileSystemComplete,
140       this,
141       callback));
142   Call<PpapiPluginMsg_FileSystem_InitIsolatedFileSystemReply>(BROWSER,
143       PpapiHostMsg_FileSystem_InitIsolatedFileSystem(fsid, type),
144       base::Bind(&FileSystemResource::InitIsolatedFileSystemComplete,
145       this,
146       callback));
147   return PP_OK_COMPLETIONPENDING;
148 }
149 
OpenComplete(scoped_refptr<TrackedCallback> callback,const ResourceMessageReplyParams & params)150 void FileSystemResource::OpenComplete(
151     scoped_refptr<TrackedCallback> callback,
152     const ResourceMessageReplyParams& params) {
153   ++callback_count_;
154   // Prioritize worse result since only one status can be returned.
155   if (params.result() != PP_OK)
156     callback_result_ = params.result();
157   // Received callback from browser and renderer.
158   if (callback_count_ == 2)
159     callback->Run(callback_result_);
160 }
161 
InitIsolatedFileSystemComplete(const base::Callback<void (int32_t)> & callback,const ResourceMessageReplyParams & params)162 void FileSystemResource::InitIsolatedFileSystemComplete(
163     const base::Callback<void(int32_t)>& callback,
164     const ResourceMessageReplyParams& params) {
165   ++callback_count_;
166   // Prioritize worse result since only one status can be returned.
167   if (params.result() != PP_OK)
168     callback_result_ = params.result();
169   // Received callback from browser and renderer.
170   if (callback_count_ == 2)
171     callback.Run(callback_result_);
172 }
173 
ReserveQuota(int64_t amount)174 void FileSystemResource::ReserveQuota(int64_t amount) {
175   DCHECK(!reserving_quota_);
176   reserving_quota_ = true;
177 
178   FileGrowthMap file_growths;
179   for (std::set<PP_Resource>::iterator it = files_.begin();
180        it != files_.end(); ++it) {
181     EnterResourceNoLock<PPB_FileIO_API> enter(*it, true);
182     if (enter.failed()) {
183       NOTREACHED();
184       continue;
185     }
186     PPB_FileIO_API* file_io_api = enter.object();
187     file_growths[*it] = FileGrowth(
188         file_io_api->GetMaxWrittenOffset(),
189         file_io_api->GetAppendModeWriteAmount());
190   }
191   Call<PpapiPluginMsg_FileSystem_ReserveQuotaReply>(BROWSER,
192       PpapiHostMsg_FileSystem_ReserveQuota(amount, file_growths),
193       base::Bind(&FileSystemResource::ReserveQuotaComplete,
194                  this));
195 }
196 
ReserveQuotaComplete(const ResourceMessageReplyParams & params,int64_t amount,const FileSizeMap & file_sizes)197 void FileSystemResource::ReserveQuotaComplete(
198     const ResourceMessageReplyParams& params,
199     int64_t amount,
200     const FileSizeMap& file_sizes) {
201   DCHECK(reserving_quota_);
202   reserving_quota_ = false;
203   reserved_quota_ = amount;
204 
205   for (FileSizeMap::const_iterator it = file_sizes.begin();
206        it != file_sizes.end(); ++it) {
207     EnterResourceNoLock<PPB_FileIO_API> enter(it->first, true);
208 
209     // It is possible that the host has sent an offset for a file that has been
210     // destroyed in the plugin. Ignore it.
211     if (enter.failed())
212       continue;
213     PPB_FileIO_API* file_io_api = enter.object();
214     file_io_api->SetMaxWrittenOffset(it->second);
215     file_io_api->SetAppendModeWriteAmount(0);
216   }
217 
218   DCHECK(!pending_quota_requests_.empty());
219   // If we can't grant the first request after refreshing reserved_quota_, then
220   // fail all pending quota requests to avoid an infinite refresh/fail loop.
221   bool fail_all = reserved_quota_ < pending_quota_requests_.front().amount;
222   while (!pending_quota_requests_.empty()) {
223     QuotaRequest& request = pending_quota_requests_.front();
224     if (fail_all) {
225       request.callback.Run(0);
226       pending_quota_requests_.pop();
227     } else if (reserved_quota_ >= request.amount) {
228       reserved_quota_ -= request.amount;
229       request.callback.Run(request.amount);
230       pending_quota_requests_.pop();
231     } else {
232       // Refresh the quota reservation for the first pending request that we
233       // can't satisfy.
234       ReserveQuota(request.amount);
235       break;
236     }
237   }
238 }
239 
240 }  // namespace proxy
241 }  // namespace ppapi
242