cc: Added inline to Tile::IsReadyToDraw
[chromium-blink-merge.git] / ppapi / proxy / file_io_resource.cc
blob76ee51c4e9ca01560bdc8bfcdde65c33117d587a
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 "ppapi/proxy/file_io_resource.h"
7 #include "base/bind.h"
8 #include "base/task_runner_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/array_writer.h"
13 #include "ppapi/shared_impl/file_type_conversion.h"
14 #include "ppapi/shared_impl/ppapi_globals.h"
15 #include "ppapi/shared_impl/proxy_lock.h"
16 #include "ppapi/shared_impl/resource_tracker.h"
17 #include "ppapi/thunk/enter.h"
18 #include "ppapi/thunk/ppb_file_ref_api.h"
20 using ppapi::thunk::EnterResourceNoLock;
21 using ppapi::thunk::PPB_FileIO_API;
22 using ppapi::thunk::PPB_FileRef_API;
24 namespace {
26 // We must allocate a buffer sized according to the request of the plugin. To
27 // reduce the chance of out-of-memory errors, we cap the read size to 32MB.
28 // This is OK since the API specifies that it may perform a partial read.
29 static const int32_t kMaxReadSize = 32 * 1024 * 1024; // 32MB
31 // An adapter to let Read() share the same implementation with ReadToArray().
32 void* DummyGetDataBuffer(void* user_data, uint32_t count, uint32_t size) {
33 return user_data;
36 // File thread task to close the file handle.
37 void DoClose(base::PlatformFile file) {
38 base::ClosePlatformFile(file);
41 } // namespace
43 namespace ppapi {
44 namespace proxy {
46 FileIOResource::QueryOp::QueryOp(PP_FileHandle file_handle)
47 : file_handle_(file_handle) {
50 FileIOResource::QueryOp::~QueryOp() {
53 int32_t FileIOResource::QueryOp::DoWork() {
54 return base::GetPlatformFileInfo(file_handle_, &file_info_) ?
55 PP_OK : PP_ERROR_FAILED;
58 FileIOResource::ReadOp::ReadOp(PP_FileHandle file_handle,
59 int64_t offset,
60 int32_t bytes_to_read)
61 : file_handle_(file_handle),
62 offset_(offset),
63 bytes_to_read_(bytes_to_read) {
66 FileIOResource::ReadOp::~ReadOp() {
69 int32_t FileIOResource::ReadOp::DoWork() {
70 DCHECK(!buffer_.get());
71 buffer_.reset(new char[bytes_to_read_]);
72 return base::ReadPlatformFile(
73 file_handle_, offset_, buffer_.get(), bytes_to_read_);
76 FileIOResource::FileIOResource(Connection connection, PP_Instance instance)
77 : PluginResource(connection, instance),
78 file_handle_(base::kInvalidPlatformFileValue),
79 file_system_type_(PP_FILESYSTEMTYPE_INVALID) {
80 SendCreate(RENDERER, PpapiHostMsg_FileIO_Create());
83 FileIOResource::~FileIOResource() {
84 CloseFileHandle();
87 PPB_FileIO_API* FileIOResource::AsPPB_FileIO_API() {
88 return this;
91 int32_t FileIOResource::Open(PP_Resource file_ref,
92 int32_t open_flags,
93 scoped_refptr<TrackedCallback> callback) {
94 EnterResourceNoLock<PPB_FileRef_API> enter(file_ref, true);
95 if (enter.failed())
96 return PP_ERROR_BADRESOURCE;
98 PPB_FileRef_API* file_ref_api = enter.object();
99 PP_FileSystemType type = file_ref_api->GetFileSystemType();
100 if (type != PP_FILESYSTEMTYPE_LOCALPERSISTENT &&
101 type != PP_FILESYSTEMTYPE_LOCALTEMPORARY &&
102 type != PP_FILESYSTEMTYPE_EXTERNAL &&
103 type != PP_FILESYSTEMTYPE_ISOLATED) {
104 NOTREACHED();
105 return PP_ERROR_FAILED;
107 file_system_type_ = type;
109 int32_t rv = state_manager_.CheckOperationState(
110 FileIOStateManager::OPERATION_EXCLUSIVE, false);
111 if (rv != PP_OK)
112 return rv;
114 Call<PpapiPluginMsg_FileIO_OpenReply>(RENDERER,
115 PpapiHostMsg_FileIO_Open(
116 enter.resource()->host_resource().host_resource(),
117 open_flags),
118 base::Bind(&FileIOResource::OnPluginMsgOpenFileComplete, this,
119 callback));
121 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
122 return PP_OK_COMPLETIONPENDING;
125 int32_t FileIOResource::Query(PP_FileInfo* info,
126 scoped_refptr<TrackedCallback> callback) {
127 int32_t rv = state_manager_.CheckOperationState(
128 FileIOStateManager::OPERATION_EXCLUSIVE, true);
129 if (rv != PP_OK)
130 return rv;
131 if (!info)
132 return PP_ERROR_BADARGUMENT;
133 if (file_handle_ == base::kInvalidPlatformFileValue)
134 return PP_ERROR_FAILED;
136 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
137 scoped_refptr<QueryOp> query_op(new QueryOp(file_handle_));
139 // If the callback is blocking, perform the task on the calling thread.
140 if (callback->is_blocking()) {
141 int32_t result;
143 // Release the proxy lock while making a potentially slow file call.
144 ProxyAutoUnlock unlock;
145 result = query_op->DoWork();
147 return OnQueryComplete(query_op, info, result);
150 // For the non-blocking case, post a task to the file thread and add a
151 // completion task to write the result.
152 base::PostTaskAndReplyWithResult(
153 PpapiGlobals::Get()->GetFileTaskRunner(pp_instance()),
154 FROM_HERE,
155 Bind(&FileIOResource::QueryOp::DoWork, query_op),
156 RunWhileLocked(Bind(&TrackedCallback::Run, callback)));
157 callback->set_completion_task(
158 Bind(&FileIOResource::OnQueryComplete, this, query_op, info));
160 return PP_OK_COMPLETIONPENDING;
163 int32_t FileIOResource::Touch(PP_Time last_access_time,
164 PP_Time last_modified_time,
165 scoped_refptr<TrackedCallback> callback) {
166 int32_t rv = state_manager_.CheckOperationState(
167 FileIOStateManager::OPERATION_EXCLUSIVE, true);
168 if (rv != PP_OK)
169 return rv;
171 Call<PpapiPluginMsg_FileIO_GeneralReply>(RENDERER,
172 PpapiHostMsg_FileIO_Touch(last_access_time, last_modified_time),
173 base::Bind(&FileIOResource::OnPluginMsgGeneralComplete, this,
174 callback));
176 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
177 return PP_OK_COMPLETIONPENDING;
180 int32_t FileIOResource::Read(int64_t offset,
181 char* buffer,
182 int32_t bytes_to_read,
183 scoped_refptr<TrackedCallback> callback) {
184 int32_t rv = state_manager_.CheckOperationState(
185 FileIOStateManager::OPERATION_READ, true);
186 if (rv != PP_OK)
187 return rv;
189 PP_ArrayOutput output_adapter;
190 output_adapter.GetDataBuffer = &DummyGetDataBuffer;
191 output_adapter.user_data = buffer;
192 return ReadValidated(offset, bytes_to_read, output_adapter, callback);
195 int32_t FileIOResource::ReadToArray(int64_t offset,
196 int32_t max_read_length,
197 PP_ArrayOutput* array_output,
198 scoped_refptr<TrackedCallback> callback) {
199 DCHECK(array_output);
200 int32_t rv = state_manager_.CheckOperationState(
201 FileIOStateManager::OPERATION_READ, true);
202 if (rv != PP_OK)
203 return rv;
205 return ReadValidated(offset, max_read_length, *array_output, callback);
208 int32_t FileIOResource::Write(int64_t offset,
209 const char* buffer,
210 int32_t bytes_to_write,
211 scoped_refptr<TrackedCallback> callback) {
212 int32_t rv = state_manager_.CheckOperationState(
213 FileIOStateManager::OPERATION_WRITE, true);
214 if (rv != PP_OK)
215 return rv;
217 // TODO(brettw) it would be nice to use a shared memory buffer for large
218 // writes rather than having to copy to a string (which will involve a number
219 // of extra copies to serialize over IPC).
220 Call<PpapiPluginMsg_FileIO_GeneralReply>(RENDERER,
221 PpapiHostMsg_FileIO_Write(offset, std::string(buffer, bytes_to_write)),
222 base::Bind(&FileIOResource::OnPluginMsgGeneralComplete, this,
223 callback));
225 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_WRITE);
226 return PP_OK_COMPLETIONPENDING;
229 int32_t FileIOResource::SetLength(int64_t length,
230 scoped_refptr<TrackedCallback> callback) {
231 int32_t rv = state_manager_.CheckOperationState(
232 FileIOStateManager::OPERATION_EXCLUSIVE, true);
233 if (rv != PP_OK)
234 return rv;
236 Call<PpapiPluginMsg_FileIO_GeneralReply>(RENDERER,
237 PpapiHostMsg_FileIO_SetLength(length),
238 base::Bind(&FileIOResource::OnPluginMsgGeneralComplete, this,
239 callback));
241 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
242 return PP_OK_COMPLETIONPENDING;
245 int32_t FileIOResource::Flush(scoped_refptr<TrackedCallback> callback) {
246 int32_t rv = state_manager_.CheckOperationState(
247 FileIOStateManager::OPERATION_EXCLUSIVE, true);
248 if (rv != PP_OK)
249 return rv;
251 Call<PpapiPluginMsg_FileIO_GeneralReply>(RENDERER,
252 PpapiHostMsg_FileIO_Flush(),
253 base::Bind(&FileIOResource::OnPluginMsgGeneralComplete, this,
254 callback));
256 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
257 return PP_OK_COMPLETIONPENDING;
260 void FileIOResource::Close() {
261 CloseFileHandle();
262 Post(RENDERER, PpapiHostMsg_FileIO_Close());
265 int32_t FileIOResource::GetOSFileDescriptor() {
266 int32_t file_descriptor;
267 // Only available when running in process.
268 SyncCall<PpapiPluginMsg_FileIO_GetOSFileDescriptorReply>(
269 RENDERER, PpapiHostMsg_FileIO_GetOSFileDescriptor(), &file_descriptor);
270 return file_descriptor;
273 int32_t FileIOResource::RequestOSFileHandle(
274 PP_FileHandle* handle,
275 scoped_refptr<TrackedCallback> callback) {
276 int32_t rv = state_manager_.CheckOperationState(
277 FileIOStateManager::OPERATION_EXCLUSIVE, true);
278 if (rv != PP_OK)
279 return rv;
281 Call<PpapiPluginMsg_FileIO_RequestOSFileHandleReply>(RENDERER,
282 PpapiHostMsg_FileIO_RequestOSFileHandle(),
283 base::Bind(&FileIOResource::OnPluginMsgRequestOSFileHandleComplete, this,
284 callback, handle));
286 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
287 return PP_OK_COMPLETIONPENDING;
290 int32_t FileIOResource::WillWrite(int64_t offset,
291 int32_t bytes_to_write,
292 scoped_refptr<TrackedCallback> callback) {
293 Call<PpapiPluginMsg_FileIO_GeneralReply>(RENDERER,
294 PpapiHostMsg_FileIO_WillWrite(offset, bytes_to_write),
295 base::Bind(&FileIOResource::OnPluginMsgGeneralComplete, this, callback));
297 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
298 return PP_OK_COMPLETIONPENDING;
301 int32_t FileIOResource::WillSetLength(int64_t length,
302 scoped_refptr<TrackedCallback> callback) {
303 Call<PpapiPluginMsg_FileIO_GeneralReply>(RENDERER,
304 PpapiHostMsg_FileIO_WillSetLength(length),
305 base::Bind(&FileIOResource::OnPluginMsgGeneralComplete, this, callback));
307 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
308 return PP_OK_COMPLETIONPENDING;
311 int32_t FileIOResource::ReadValidated(int64_t offset,
312 int32_t bytes_to_read,
313 const PP_ArrayOutput& array_output,
314 scoped_refptr<TrackedCallback> callback) {
315 if (bytes_to_read < 0)
316 return PP_ERROR_FAILED;
317 if (file_handle_ == base::kInvalidPlatformFileValue)
318 return PP_ERROR_FAILED;
320 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_READ);
322 bytes_to_read = std::min(bytes_to_read, kMaxReadSize);
323 scoped_refptr<ReadOp> read_op(
324 new ReadOp(file_handle_, offset, bytes_to_read));
325 if (callback->is_blocking()) {
326 int32_t result;
328 // Release the proxy lock while making a potentially slow file call.
329 ProxyAutoUnlock unlock;
330 result = read_op->DoWork();
332 return OnReadComplete(read_op, array_output, result);
335 // For the non-blocking case, post a task to the file thread.
336 base::PostTaskAndReplyWithResult(
337 PpapiGlobals::Get()->GetFileTaskRunner(pp_instance()),
338 FROM_HERE,
339 Bind(&FileIOResource::ReadOp::DoWork, read_op),
340 RunWhileLocked(Bind(&TrackedCallback::Run, callback)));
341 callback->set_completion_task(
342 Bind(&FileIOResource::OnReadComplete, this, read_op, array_output));
344 return PP_OK_COMPLETIONPENDING;
347 void FileIOResource::CloseFileHandle() {
348 if (file_handle_ != base::kInvalidPlatformFileValue) {
349 // Close our local fd on the file thread.
350 base::TaskRunner* file_task_runner =
351 PpapiGlobals::Get()->GetFileTaskRunner(pp_instance());
352 file_task_runner->PostTask(FROM_HERE,
353 base::Bind(&DoClose, file_handle_));
355 file_handle_ = base::kInvalidPlatformFileValue;
359 int32_t FileIOResource::OnQueryComplete(scoped_refptr<QueryOp> query_op,
360 PP_FileInfo* info,
361 int32_t result) {
362 DCHECK(state_manager_.get_pending_operation() ==
363 FileIOStateManager::OPERATION_EXCLUSIVE);
365 if (result == PP_OK) {
366 // This writes the file info into the plugin's PP_FileInfo struct.
367 ppapi::PlatformFileInfoToPepperFileInfo(query_op->file_info(),
368 file_system_type_,
369 info);
371 state_manager_.SetOperationFinished();
372 return result;
375 int32_t FileIOResource::OnReadComplete(scoped_refptr<ReadOp> read_op,
376 PP_ArrayOutput array_output,
377 int32_t result) {
378 DCHECK(state_manager_.get_pending_operation() ==
379 FileIOStateManager::OPERATION_READ);
380 if (result >= 0) {
381 ArrayWriter output;
382 output.set_pp_array_output(array_output);
383 if (output.is_valid())
384 output.StoreArray(read_op->buffer(), result);
385 else
386 result = PP_ERROR_FAILED;
387 } else {
388 // The read operation failed.
389 result = PP_ERROR_FAILED;
391 state_manager_.SetOperationFinished();
392 return result;
395 void FileIOResource::OnPluginMsgGeneralComplete(
396 scoped_refptr<TrackedCallback> callback,
397 const ResourceMessageReplyParams& params) {
398 DCHECK(state_manager_.get_pending_operation() ==
399 FileIOStateManager::OPERATION_EXCLUSIVE ||
400 state_manager_.get_pending_operation() ==
401 FileIOStateManager::OPERATION_WRITE);
402 // End this operation now, so the user's callback can execute another FileIO
403 // operation, assuming there are no other pending operations.
404 state_manager_.SetOperationFinished();
405 callback->Run(params.result());
408 void FileIOResource::OnPluginMsgOpenFileComplete(
409 scoped_refptr<TrackedCallback> callback,
410 const ResourceMessageReplyParams& params) {
411 DCHECK(state_manager_.get_pending_operation() ==
412 FileIOStateManager::OPERATION_EXCLUSIVE);
413 if (params.result() == PP_OK)
414 state_manager_.SetOpenSucceed();
416 int32_t result = params.result();
417 IPC::PlatformFileForTransit transit_file;
418 if ((result == PP_OK) && params.TakeFileHandleAtIndex(0, &transit_file))
419 file_handle_ = IPC::PlatformFileForTransitToPlatformFile(transit_file);
420 // End this operation now, so the user's callback can execute another FileIO
421 // operation, assuming there are no other pending operations.
422 state_manager_.SetOperationFinished();
423 callback->Run(result);
426 void FileIOResource::OnPluginMsgRequestOSFileHandleComplete(
427 scoped_refptr<TrackedCallback> callback,
428 PP_FileHandle* output_handle,
429 const ResourceMessageReplyParams& params) {
430 DCHECK(state_manager_.get_pending_operation() ==
431 FileIOStateManager::OPERATION_EXCLUSIVE);
433 if (!TrackedCallback::IsPending(callback)) {
434 state_manager_.SetOperationFinished();
435 return;
438 int32_t result = params.result();
439 IPC::PlatformFileForTransit transit_file;
440 if (!params.TakeFileHandleAtIndex(0, &transit_file))
441 result = PP_ERROR_FAILED;
442 *output_handle = IPC::PlatformFileForTransitToPlatformFile(transit_file);
444 // End this operation now, so the user's callback can execute another FileIO
445 // operation, assuming there are no other pending operations.
446 state_manager_.SetOperationFinished();
447 callback->Run(result);
450 } // namespace proxy
451 } // namespace ppapi