Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(456)

Side by Side Diff: media/cdm/ppapi/cdm_file_io_impl.cc

Issue 545983005: CdmFileIOImpl: Refactor Write() implementation. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: comments addressed Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "media/cdm/ppapi/cdm_file_io_impl.h" 5 #include "media/cdm/ppapi/cdm_file_io_impl.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <sstream> 8 #include <sstream>
9 9
10 #include "media/cdm/ppapi/cdm_logging.h" 10 #include "media/cdm/ppapi/cdm_logging.h"
11 #include "ppapi/c/pp_errors.h" 11 #include "ppapi/c/pp_errors.h"
12 #include "ppapi/cpp/dev/url_util_dev.h" 12 #include "ppapi/cpp/dev/url_util_dev.h"
13 13
14 namespace media { 14 namespace media {
15 15
16 const int kReadSize = 4 * 1024; // Arbitrary choice. 16 // Arbitrary choice based on the following heuristic ideas:
17 // - not too big to avoid unnecessarily large memory allocation;
18 // - not too small to avoid breaking most reads into multiple read operations.
19 const int kReadSize = 8 * 1024;
17 20
18 // Call func_call and check the result. If the result is not 21 // Call func_call and check the result. If the result is not
19 // PP_OK_COMPLETIONPENDING, print out logs, call OnError() and return. 22 // PP_OK_COMPLETIONPENDING, print out logs, call OnError() and return.
20 #define CHECK_PP_OK_COMPLETIONPENDING(func_call, error_type) \ 23 #define CHECK_PP_OK_COMPLETIONPENDING(func_call, error_type) \
21 do { \ 24 do { \
22 int32_t result = func_call; \ 25 int32_t result = func_call; \
23 PP_DCHECK(result != PP_OK); \ 26 PP_DCHECK(result != PP_OK); \
24 if (result != PP_OK_COMPLETIONPENDING) { \ 27 if (result != PP_OK_COMPLETIONPENDING) { \
25 CDM_DLOG() << #func_call << " failed with result: " << result; \ 28 CDM_DLOG() << #func_call << " failed with result: " << result; \
29 state_ = STATE_ERROR; \
26 OnError(error_type); \ 30 OnError(error_type); \
27 return; \ 31 return; \
28 } \ 32 } \
29 } while (0) 33 } while (0)
30 34
31 #if !defined(NDEBUG) 35 #if !defined(NDEBUG)
32 // PPAPI calls should only be made on the main thread. In this file, main thread 36 // PPAPI calls should only be made on the main thread. In this file, main thread
33 // checking is only performed in public APIs and the completion callbacks. This 37 // checking is only performed in public APIs and the completion callbacks. This
34 // ensures all functions are running on the main thread since internal methods 38 // ensures all functions are running on the main thread since internal methods
35 // are called either by the public APIs or by the completion callbacks. 39 // are called either by the public APIs or by the completion callbacks.
(...skipping 16 matching lines...) Expand all
52 } 56 }
53 57
54 CdmFileIOImpl::ResourceTracker::~ResourceTracker() { 58 CdmFileIOImpl::ResourceTracker::~ResourceTracker() {
55 delete CdmFileIOImpl::file_lock_map_; 59 delete CdmFileIOImpl::file_lock_map_;
56 } 60 }
57 61
58 CdmFileIOImpl::CdmFileIOImpl( 62 CdmFileIOImpl::CdmFileIOImpl(
59 cdm::FileIOClient* client, 63 cdm::FileIOClient* client,
60 PP_Instance pp_instance, 64 PP_Instance pp_instance,
61 const pp::CompletionCallback& first_file_read_cb) 65 const pp::CompletionCallback& first_file_read_cb)
62 : state_(FILE_UNOPENED), 66 : state_(STATE_UNOPENED),
63 client_(client), 67 client_(client),
64 pp_instance_handle_(pp_instance), 68 pp_instance_handle_(pp_instance),
65 callback_factory_(this),
66 io_offset_(0), 69 io_offset_(0),
67 first_file_read_reported_(false), 70 first_file_read_reported_(false),
68 first_file_read_cb_(first_file_read_cb) { 71 first_file_read_cb_(first_file_read_cb),
72 callback_factory_(this) {
69 PP_DCHECK(IsMainThread()); 73 PP_DCHECK(IsMainThread());
70 PP_DCHECK(pp_instance); // 0 indicates a "NULL handle". 74 PP_DCHECK(pp_instance); // 0 indicates a "NULL handle".
71 } 75 }
72 76
73 CdmFileIOImpl::~CdmFileIOImpl() { 77 CdmFileIOImpl::~CdmFileIOImpl() {
74 PP_DCHECK(state_ == FILE_CLOSED); 78 // The destructor is private. |this| can only be destructed through Close().
79 PP_DCHECK(state_ == STATE_CLOSED);
75 } 80 }
76 81
77 // Call sequence: Open() -> OpenFileSystem() -> OpenFile() -> FILE_OPENED. 82 // Call sequence: Open() -> OpenFileSystem() -> STATE_FILE_SYSTEM_OPENED.
83 // Note: This only stores file name and opens the file system. The real file
84 // open is deferred to when Read() or Write() is called.
78 void CdmFileIOImpl::Open(const char* file_name, uint32_t file_name_size) { 85 void CdmFileIOImpl::Open(const char* file_name, uint32_t file_name_size) {
79 CDM_DLOG() << __FUNCTION__; 86 CDM_DLOG() << __FUNCTION__;
80 PP_DCHECK(IsMainThread()); 87 PP_DCHECK(IsMainThread());
81 88
82 if (state_ != FILE_UNOPENED) { 89 if (state_ != STATE_UNOPENED) {
83 CDM_DLOG() << "Open() called in an invalid state."; 90 CDM_DLOG() << "Open() called in an invalid state.";
84 OnError(OPEN_ERROR); 91 OnError(OPEN_ERROR);
85 return; 92 return;
86 } 93 }
87 94
88 // File name should not contain any path separators. 95 // File name should not (1) be empty, (2) start with '_', or (3) contain any
96 // path separators.
89 std::string file_name_str(file_name, file_name_size); 97 std::string file_name_str(file_name, file_name_size);
90 if (file_name_str.find('/') != std::string::npos || 98 if (file_name_str.empty() ||
99 file_name_str[0] == '_' ||
100 file_name_str.find('/') != std::string::npos ||
91 file_name_str.find('\\') != std::string::npos) { 101 file_name_str.find('\\') != std::string::npos) {
92 CDM_DLOG() << "Invalid file name."; 102 CDM_DLOG() << "Invalid file name.";
103 state_ = STATE_ERROR;
93 OnError(OPEN_ERROR); 104 OnError(OPEN_ERROR);
94 return; 105 return;
95 } 106 }
96 107
97 // pp::FileRef only accepts path that begins with a '/' character. 108 // pp::FileRef only accepts path that begins with a '/' character.
98 file_name_ = '/' + file_name_str; 109 file_name_ = '/' + file_name_str;
99 110
100 if (!AcquireFileLock()) { 111 if (!AcquireFileLock()) {
101 CDM_DLOG() << "File is in use by other cdm::FileIO objects."; 112 CDM_DLOG() << "File is in use by other cdm::FileIO objects.";
102 OnError(OPEN_WHILE_IN_USE); 113 OnError(OPEN_WHILE_IN_USE);
103 return; 114 return;
104 } 115 }
105 116
106 state_ = OPENING_FILE_SYSTEM; 117 state_ = STATE_OPENING_FILE_SYSTEM;
107 OpenFileSystem(); 118 OpenFileSystem();
108 } 119 }
109 120
110 // Call sequence: 121 // Call sequence:
111 // finished 122 // Read() -> OpenFileForRead() -> ReadFile() -> Done.
112 // Read() -> ReadFile() -> OnFileRead() ----------> Done.
113 // ^ |
114 // | not finished |
115 // |--------------|
116 void CdmFileIOImpl::Read() { 123 void CdmFileIOImpl::Read() {
117 CDM_DLOG() << __FUNCTION__; 124 CDM_DLOG() << __FUNCTION__;
118 PP_DCHECK(IsMainThread()); 125 PP_DCHECK(IsMainThread());
119 126
120 if (state_ == READING_FILE || state_ == WRITING_FILE) { 127 if (state_ == STATE_READING || state_ == STATE_WRITING) {
121 CDM_DLOG() << "Read() called during pending read/write."; 128 CDM_DLOG() << "Read() called during pending read/write.";
122 OnError(READ_WHILE_IN_USE); 129 OnError(READ_WHILE_IN_USE);
123 return; 130 return;
124 } 131 }
125 132
126 if (state_ != FILE_OPENED) { 133 if (state_ != STATE_FILE_SYSTEM_OPENED) {
127 CDM_DLOG() << "Read() called in an invalid state."; 134 CDM_DLOG() << "Read() called in an invalid state.";
128 OnError(READ_ERROR); 135 OnError(READ_ERROR);
129 return; 136 return;
130 } 137 }
131 138
139 PP_DCHECK(io_offset_ == 0);
132 PP_DCHECK(io_buffer_.empty()); 140 PP_DCHECK(io_buffer_.empty());
133 PP_DCHECK(cumulative_read_buffer_.empty()); 141 PP_DCHECK(cumulative_read_buffer_.empty());
134
135 io_buffer_.resize(kReadSize); 142 io_buffer_.resize(kReadSize);
136 io_offset_ = 0; 143 io_offset_ = 0;
137 144
138 state_ = READING_FILE; 145 state_ = STATE_READING;
139 ReadFile(); 146 OpenFileForRead();
140 } 147 }
141 148
142 // Call sequence: 149 // Call sequence:
143 // finished 150 // Write() -> OpenTempFileForWrite() -> WriteTempFile() -> RenameTempFile().
144 // Write() -> WriteFile() -> OnFileWritten() ----------> Done. 151 // The file name of the temporary file is /_<requested_file_name>.
145 // ^ |
146 // | | not finished
147 // |------------------|
148 void CdmFileIOImpl::Write(const uint8_t* data, uint32_t data_size) { 152 void CdmFileIOImpl::Write(const uint8_t* data, uint32_t data_size) {
149 CDM_DLOG() << __FUNCTION__; 153 CDM_DLOG() << __FUNCTION__;
150 PP_DCHECK(IsMainThread()); 154 PP_DCHECK(IsMainThread());
151 155
152 if (state_ == READING_FILE || state_ == WRITING_FILE) { 156 if (state_ == STATE_READING || state_ == STATE_WRITING) {
153 CDM_DLOG() << "Write() called during pending read/write."; 157 CDM_DLOG() << "Write() called during pending read/write.";
154 OnError(WRITE_WHILE_IN_USE); 158 OnError(WRITE_WHILE_IN_USE);
155 return; 159 return;
156 } 160 }
157 161
158 if (state_ != FILE_OPENED) { 162 if (state_ != STATE_FILE_SYSTEM_OPENED) {
159 CDM_DLOG() << "Write() called in an invalid state."; 163 CDM_DLOG() << "Write() called in an invalid state.";
160 OnError(WRITE_ERROR); 164 OnError(WRITE_ERROR);
161 return; 165 return;
162 } 166 }
163 167
164 PP_DCHECK(io_offset_ == 0); 168 PP_DCHECK(io_offset_ == 0);
165 PP_DCHECK(io_buffer_.empty()); 169 PP_DCHECK(io_buffer_.empty());
166 if (data_size > 0) 170 if (data_size > 0)
167 io_buffer_.assign(data, data + data_size); 171 io_buffer_.assign(data, data + data_size);
168 else 172 else
169 PP_DCHECK(!data); 173 PP_DCHECK(!data);
170 174
171 state_ = WRITING_FILE; 175 state_ = STATE_WRITING;
172 176 OpenTempFileForWrite();
173 // Always SetLength() in case |data_size| is less than the file size.
174 SetLength(data_size);
175 } 177 }
176 178
177 void CdmFileIOImpl::Close() { 179 void CdmFileIOImpl::Close() {
178 CDM_DLOG() << __FUNCTION__; 180 CDM_DLOG() << __FUNCTION__;
179 PP_DCHECK(IsMainThread()); 181 PP_DCHECK(IsMainThread());
180 PP_DCHECK(state_ != FILE_CLOSED); 182 PP_DCHECK(state_ != STATE_CLOSED);
181 CloseFile(); 183 Reset();
184 state_ = STATE_CLOSED;
182 ReleaseFileLock(); 185 ReleaseFileLock();
183 // All pending callbacks are canceled since |callback_factory_| is destroyed. 186 // All pending callbacks are canceled since |callback_factory_| is destroyed.
184 delete this; 187 delete this;
185 } 188 }
186 189
187 bool CdmFileIOImpl::SetFileID() { 190 bool CdmFileIOImpl::SetFileID() {
188 PP_DCHECK(file_id_.empty()); 191 PP_DCHECK(file_id_.empty());
189 PP_DCHECK(!file_name_.empty() && file_name_[0] == '/'); 192 PP_DCHECK(!file_name_.empty() && file_name_[0] == '/');
190 193
191 // Not taking ownership of |url_util_dev| (which is a singleton). 194 // Not taking ownership of |url_util_dev| (which is a singleton).
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
230 233
231 if (!file_lock_map_) 234 if (!file_lock_map_)
232 return; 235 return;
233 236
234 FileLockMap::iterator found = file_lock_map_->find(file_id_); 237 FileLockMap::iterator found = file_lock_map_->find(file_id_);
235 if (found != file_lock_map_->end() && found->second) 238 if (found != file_lock_map_->end() && found->second)
236 found->second = false; 239 found->second = false;
237 } 240 }
238 241
239 void CdmFileIOImpl::OpenFileSystem() { 242 void CdmFileIOImpl::OpenFileSystem() {
240 PP_DCHECK(state_ == OPENING_FILE_SYSTEM); 243 PP_DCHECK(state_ == STATE_OPENING_FILE_SYSTEM);
241 244
242 pp::CompletionCallbackWithOutput<pp::FileSystem> cb = 245 pp::CompletionCallbackWithOutput<pp::FileSystem> cb =
243 callback_factory_.NewCallbackWithOutput( 246 callback_factory_.NewCallbackWithOutput(
244 &CdmFileIOImpl::OnFileSystemOpened); 247 &CdmFileIOImpl::OnFileSystemOpened);
245 isolated_file_system_ = pp::IsolatedFileSystemPrivate( 248 isolated_file_system_ = pp::IsolatedFileSystemPrivate(
246 pp_instance_handle_, PP_ISOLATEDFILESYSTEMTYPE_PRIVATE_PLUGINPRIVATE); 249 pp_instance_handle_, PP_ISOLATEDFILESYSTEMTYPE_PRIVATE_PLUGINPRIVATE);
247 250
248 CHECK_PP_OK_COMPLETIONPENDING(isolated_file_system_.Open(cb), OPEN_ERROR); 251 CHECK_PP_OK_COMPLETIONPENDING(isolated_file_system_.Open(cb), OPEN_ERROR);
249 } 252 }
250 253
251 void CdmFileIOImpl::OnFileSystemOpened(int32_t result, 254 void CdmFileIOImpl::OnFileSystemOpened(int32_t result,
252 pp::FileSystem file_system) { 255 pp::FileSystem file_system) {
253 PP_DCHECK(IsMainThread()); 256 PP_DCHECK(IsMainThread());
254 PP_DCHECK(state_ == OPENING_FILE_SYSTEM); 257 PP_DCHECK(state_ == STATE_OPENING_FILE_SYSTEM);
255 258
256 if (result != PP_OK) { 259 if (result != PP_OK) {
257 CDM_DLOG() << "File system open failed asynchronously."; 260 CDM_DLOG() << "File system open failed asynchronously.";
258 ReleaseFileLock(); 261 ReleaseFileLock();
262 state_ = STATE_ERROR;
259 OnError(OPEN_ERROR); 263 OnError(OPEN_ERROR);
260 return; 264 return;
261 } 265 }
262 266
263 file_system_ = file_system; 267 file_system_ = file_system;
264 state_ = OPENING_FILE; 268
265 OpenFile(); 269 state_ = STATE_FILE_SYSTEM_OPENED;
270 client_->OnOpenComplete(cdm::FileIOClient::kSuccess);
266 } 271 }
267 272
268 void CdmFileIOImpl::OpenFile() { 273 void CdmFileIOImpl::OpenFileForRead() {
269 PP_DCHECK(state_ == OPENING_FILE); 274 PP_DCHECK(state_ == STATE_READING);
270 275
276 PP_DCHECK(file_io_.is_null());
277 PP_DCHECK(file_ref_.is_null());
271 file_io_ = pp::FileIO(pp_instance_handle_); 278 file_io_ = pp::FileIO(pp_instance_handle_);
272 file_ref_ = pp::FileRef(file_system_, file_name_.c_str()); 279 file_ref_ = pp::FileRef(file_system_, file_name_.c_str());
273 int32_t file_open_flag = PP_FILEOPENFLAG_READ | 280
274 PP_FILEOPENFLAG_WRITE | 281 // Open file for read. If file doesn't exist, PP_ERROR_FILENOTFOUND will be
275 PP_FILEOPENFLAG_CREATE; 282 // returned.
283 int32_t file_open_flag = PP_FILEOPENFLAG_READ;
284
276 pp::CompletionCallback cb = 285 pp::CompletionCallback cb =
277 callback_factory_.NewCallback(&CdmFileIOImpl::OnFileOpened); 286 callback_factory_.NewCallback(&CdmFileIOImpl::OnFileOpenedForRead);
278 CHECK_PP_OK_COMPLETIONPENDING(file_io_.Open(file_ref_, file_open_flag, cb), 287 CHECK_PP_OK_COMPLETIONPENDING(file_io_.Open(file_ref_, file_open_flag, cb),
279 OPEN_ERROR); 288 READ_ERROR);
280 } 289 }
281 290
282 void CdmFileIOImpl::OnFileOpened(int32_t result) { 291 void CdmFileIOImpl::OnFileOpenedForRead(int32_t result) {
292 CDM_DLOG() << __FUNCTION__ << ": " << result;
283 PP_DCHECK(IsMainThread()); 293 PP_DCHECK(IsMainThread());
284 PP_DCHECK(state_ == OPENING_FILE); 294 PP_DCHECK(state_ == STATE_READING);
285 295
286 if (result != PP_OK) { 296 if (result != PP_OK && result != PP_ERROR_FILENOTFOUND) {
287 CDM_DLOG() << "File open failed."; 297 CDM_DLOG() << "File open failed.";
288 ReleaseFileLock(); 298 state_ = STATE_ERROR;
289 OnError(OPEN_ERROR); 299 OnError(OPEN_ERROR);
290 return; 300 return;
291 } 301 }
292 302
293 state_ = FILE_OPENED; 303 // File doesn't exist.
294 client_->OnOpenComplete(cdm::FileIOClient::kSuccess); 304 if (result == PP_ERROR_FILENOTFOUND) {
305 Reset();
306 state_ = STATE_FILE_SYSTEM_OPENED;
307 client_->OnReadComplete(cdm::FileIOClient::kSuccess, NULL, 0);
308 return;
309 }
310
311 ReadFile();
295 } 312 }
296 313
314 // Call sequence:
315 // fully read
316 // ReadFile() ---> OnFileRead() ------------> Done.
317 // ^ |
318 // | partially read |
319 // |----------------|
297 void CdmFileIOImpl::ReadFile() { 320 void CdmFileIOImpl::ReadFile() {
298 PP_DCHECK(state_ == READING_FILE); 321 PP_DCHECK(state_ == STATE_READING);
299 PP_DCHECK(!io_buffer_.empty()); 322 PP_DCHECK(!io_buffer_.empty());
300 323
301 pp::CompletionCallback cb = 324 pp::CompletionCallback cb =
302 callback_factory_.NewCallback(&CdmFileIOImpl::OnFileRead); 325 callback_factory_.NewCallback(&CdmFileIOImpl::OnFileRead);
303 CHECK_PP_OK_COMPLETIONPENDING( 326 CHECK_PP_OK_COMPLETIONPENDING(
304 file_io_.Read(io_offset_, &io_buffer_[0], io_buffer_.size(), cb), 327 file_io_.Read(io_offset_, &io_buffer_[0], io_buffer_.size(), cb),
305 READ_ERROR); 328 READ_ERROR);
306 } 329 }
307 330
308 void CdmFileIOImpl::OnFileRead(int32_t bytes_read) { 331 void CdmFileIOImpl::OnFileRead(int32_t bytes_read) {
309 CDM_DLOG() << __FUNCTION__ << ": " << bytes_read; 332 CDM_DLOG() << __FUNCTION__ << ": " << bytes_read;
310 PP_DCHECK(IsMainThread()); 333 PP_DCHECK(IsMainThread());
311 PP_DCHECK(state_ == READING_FILE); 334 PP_DCHECK(state_ == STATE_READING);
312 335
313 // 0 |bytes_read| indicates end-of-file reached. 336 // 0 |bytes_read| indicates end-of-file reached.
314 if (bytes_read < PP_OK) { 337 if (bytes_read < PP_OK) {
315 CDM_DLOG() << "Read file failed."; 338 CDM_DLOG() << "Read file failed.";
339 state_ = STATE_ERROR;
316 OnError(READ_ERROR); 340 OnError(READ_ERROR);
317 return; 341 return;
318 } 342 }
319 343
320 PP_DCHECK(static_cast<size_t>(bytes_read) <= io_buffer_.size()); 344 PP_DCHECK(static_cast<size_t>(bytes_read) <= io_buffer_.size());
321 // Append |bytes_read| in |io_buffer_| to |cumulative_read_buffer_|. 345 // Append |bytes_read| in |io_buffer_| to |cumulative_read_buffer_|.
322 cumulative_read_buffer_.insert(cumulative_read_buffer_.end(), 346 cumulative_read_buffer_.insert(cumulative_read_buffer_.end(),
323 io_buffer_.begin(), 347 io_buffer_.begin(),
324 io_buffer_.begin() + bytes_read); 348 io_buffer_.begin() + bytes_read);
325 io_offset_ += bytes_read; 349 io_offset_ += bytes_read;
326 350
327 // Not received end-of-file yet. 351 // Not received end-of-file yet. Keep reading.
328 if (bytes_read > 0) { 352 if (bytes_read > 0) {
329 ReadFile(); 353 ReadFile();
330 return; 354 return;
331 } 355 }
332 356
333 // We hit end-of-file. Return read data to the client. 357 // We hit end-of-file. Return read data to the client.
334 io_buffer_.clear(); 358
335 io_offset_ = 0;
336 // Clear |cumulative_read_buffer_| in case OnReadComplete() calls Read() or 359 // Clear |cumulative_read_buffer_| in case OnReadComplete() calls Read() or
337 // Write(). 360 // Write().
338 std::vector<char> local_buffer; 361 std::vector<char> local_buffer;
339 std::swap(cumulative_read_buffer_, local_buffer); 362 std::swap(cumulative_read_buffer_, local_buffer);
340 363
341 state_ = FILE_OPENED;
342 const uint8_t* data = local_buffer.empty() ? 364 const uint8_t* data = local_buffer.empty() ?
343 NULL : reinterpret_cast<const uint8_t*>(&local_buffer[0]); 365 NULL : reinterpret_cast<const uint8_t*>(&local_buffer[0]);
344 366
345 // Call this before OnReadComplete() so that we always have the latest file 367 // Call this before OnReadComplete() so that we always have the latest file
346 // size before CDM fires errors. 368 // size before CDM fires errors.
347 if (!first_file_read_reported_) { 369 if (!first_file_read_reported_) {
348 first_file_read_cb_.Run(local_buffer.size()); 370 first_file_read_cb_.Run(local_buffer.size());
349 first_file_read_reported_ = true; 371 first_file_read_reported_ = true;
350 } 372 }
351 373
374 Reset();
375
376 state_ = STATE_FILE_SYSTEM_OPENED;
352 client_->OnReadComplete( 377 client_->OnReadComplete(
353 cdm::FileIOClient::kSuccess, data, local_buffer.size()); 378 cdm::FileIOClient::kSuccess, data, local_buffer.size());
354 } 379 }
355 380
356 void CdmFileIOImpl::SetLength(uint32_t length) { 381 void CdmFileIOImpl::OpenTempFileForWrite() {
357 PP_DCHECK(state_ == WRITING_FILE); 382 PP_DCHECK(state_ == STATE_WRITING);
383
384 PP_DCHECK(file_name_.size() > 1 && file_name_[0] == '/');
385 // Temporary file name format: /_<requested_file_name>
386 std::string temp_file_name = "/_" + file_name_.substr(1);
387
388 PP_DCHECK(file_io_.is_null());
389 PP_DCHECK(file_ref_.is_null());
390 file_io_ = pp::FileIO(pp_instance_handle_);
391 file_ref_ = pp::FileRef(file_system_, temp_file_name.c_str());
392
393 // Create the file if it doesn't exist. Truncate the file to length 0 if it
394 // exists.
395 // TODO(xhwang): Find a good way to report to UMA cases where the temporary
396 // file already exists (due to previous interruption or failure).
397 int32_t file_open_flag = PP_FILEOPENFLAG_WRITE |
398 PP_FILEOPENFLAG_TRUNCATE |
399 PP_FILEOPENFLAG_CREATE;
358 400
359 pp::CompletionCallback cb = 401 pp::CompletionCallback cb =
360 callback_factory_.NewCallback(&CdmFileIOImpl::OnLengthSet); 402 callback_factory_.NewCallback(&CdmFileIOImpl::OnTempFileOpenedForWrite);
361 CHECK_PP_OK_COMPLETIONPENDING(file_io_.SetLength(length, cb), WRITE_ERROR); 403 CHECK_PP_OK_COMPLETIONPENDING(
404 file_io_.Open(file_ref_, file_open_flag, cb), WRITE_ERROR);
362 } 405 }
363 406
364 void CdmFileIOImpl::OnLengthSet(int32_t result) { 407 void CdmFileIOImpl::OnTempFileOpenedForWrite(int32_t result) {
365 CDM_DLOG() << __FUNCTION__ << ": " << result; 408 CDM_DLOG() << __FUNCTION__ << ": " << result;
366 PP_DCHECK(IsMainThread()); 409 PP_DCHECK(IsMainThread());
367 PP_DCHECK(state_ == WRITING_FILE); 410 PP_DCHECK(state_ == STATE_WRITING);
368 411
369 if (result != PP_OK) { 412 if (result != PP_OK) {
370 CDM_DLOG() << "File SetLength failed."; 413 CDM_DLOG() << "Open temporary file failed.";
414 state_ = STATE_ERROR;
371 OnError(WRITE_ERROR); 415 OnError(WRITE_ERROR);
372 return; 416 return;
373 } 417 }
374 418
419 // We were told to write 0 bytes (to clear the file). In this case, there's
420 // no need to write anything.
375 if (io_buffer_.empty()) { 421 if (io_buffer_.empty()) {
376 state_ = FILE_OPENED; 422 RenameTempFile();
377 client_->OnWriteComplete(cdm::FileIOClient::kSuccess);
378 return; 423 return;
379 } 424 }
380 425
381 WriteFile(); 426 PP_DCHECK(io_offset_ == 0);
427 io_offset_ = 0;
428 WriteTempFile();
382 } 429 }
383 430
384 void CdmFileIOImpl::WriteFile() { 431 // Call sequence:
385 PP_DCHECK(state_ == WRITING_FILE); 432 // fully written
433 // WriteTempFile() -> OnTempFileWritten() ---------------> RenameTempFile().
434 // ^ |
435 // | partially written |
436 // |---------------------|
437 void CdmFileIOImpl::WriteTempFile() {
438 PP_DCHECK(state_ == STATE_WRITING);
386 PP_DCHECK(io_offset_ < io_buffer_.size()); 439 PP_DCHECK(io_offset_ < io_buffer_.size());
387 440
388 pp::CompletionCallback cb = 441 pp::CompletionCallback cb =
389 callback_factory_.NewCallback(&CdmFileIOImpl::OnFileWritten); 442 callback_factory_.NewCallback(&CdmFileIOImpl::OnTempFileWritten);
390 CHECK_PP_OK_COMPLETIONPENDING(file_io_.Write(io_offset_, 443 CHECK_PP_OK_COMPLETIONPENDING(file_io_.Write(io_offset_,
391 &io_buffer_[io_offset_], 444 &io_buffer_[io_offset_],
392 io_buffer_.size() - io_offset_, 445 io_buffer_.size() - io_offset_,
393 cb), 446 cb),
394 WRITE_ERROR); 447 WRITE_ERROR);
395 } 448 }
396 449
397 void CdmFileIOImpl::OnFileWritten(int32_t bytes_written) { 450 void CdmFileIOImpl::OnTempFileWritten(int32_t bytes_written) {
398 CDM_DLOG() << __FUNCTION__ << ": " << bytes_written; 451 CDM_DLOG() << __FUNCTION__ << ": " << bytes_written;
399 PP_DCHECK(IsMainThread()); 452 PP_DCHECK(IsMainThread());
400 PP_DCHECK(state_ == WRITING_FILE); 453 PP_DCHECK(state_ == STATE_WRITING);
401 454
402 if (bytes_written <= PP_OK) { 455 if (bytes_written <= PP_OK) {
403 CDM_DLOG() << "Write file failed."; 456 CDM_DLOG() << "Write temporary file failed.";
404 OnError(READ_ERROR); 457 state_ = STATE_ERROR;
458 OnError(WRITE_ERROR);
405 return; 459 return;
406 } 460 }
407 461
408 io_offset_ += bytes_written; 462 io_offset_ += bytes_written;
409 PP_DCHECK(io_offset_ <= io_buffer_.size()); 463 PP_DCHECK(io_offset_ <= io_buffer_.size());
410 464
411 if (io_offset_ < io_buffer_.size()) { 465 if (io_offset_ < io_buffer_.size()) {
412 WriteFile(); 466 WriteTempFile();
413 return; 467 return;
414 } 468 }
415 469
416 io_buffer_.clear(); 470 // All data written. Now rename the temporary file to the real file.
417 io_offset_ = 0; 471 RenameTempFile();
418 state_ = FILE_OPENED; 472 }
473
474 void CdmFileIOImpl::RenameTempFile() {
475 PP_DCHECK(state_ == STATE_WRITING);
476
477 pp::CompletionCallback cb =
478 callback_factory_.NewCallback(&CdmFileIOImpl::OnTempFileRenamed);
479 CHECK_PP_OK_COMPLETIONPENDING(
480 file_ref_.Rename(pp::FileRef(file_system_, file_name_.c_str()), cb),
481 WRITE_ERROR);
482 }
483
484 void CdmFileIOImpl::OnTempFileRenamed(int32_t result) {
485 CDM_DLOG() << __FUNCTION__ << ": " << result;
486 PP_DCHECK(IsMainThread());
487 PP_DCHECK(state_ == STATE_WRITING);
488
489 if (result != PP_OK) {
490 CDM_DLOG() << "Rename temporary file failed.";
491 state_ = STATE_ERROR;
492 OnError(WRITE_ERROR);
493 return;
494 }
495
496 Reset();
497
498 state_ = STATE_FILE_SYSTEM_OPENED;
419 client_->OnWriteComplete(cdm::FileIOClient::kSuccess); 499 client_->OnWriteComplete(cdm::FileIOClient::kSuccess);
420 } 500 }
421 501
422 void CdmFileIOImpl::CloseFile() { 502 void CdmFileIOImpl::Reset() {
423 PP_DCHECK(IsMainThread()); 503 PP_DCHECK(IsMainThread());
424
425 state_ = FILE_CLOSED;
426
427 file_io_.Close();
428 io_buffer_.clear(); 504 io_buffer_.clear();
429 io_offset_ = 0; 505 io_offset_ = 0;
430 cumulative_read_buffer_.clear(); 506 cumulative_read_buffer_.clear();
507 file_io_.Close();
508 file_io_ = pp::FileIO();
509 file_ref_ = pp::FileRef();
431 } 510 }
432 511
433 void CdmFileIOImpl::OnError(ErrorType error_type) { 512 void CdmFileIOImpl::OnError(ErrorType error_type) {
434 // For *_WHILE_IN_USE errors, do not reset these values. Otherwise, the 513 // For *_WHILE_IN_USE errors, do not reset these values. Otherwise, the
435 // existing read/write operation will fail. 514 // existing read/write operation will fail.
436 if (error_type == READ_ERROR || error_type == WRITE_ERROR) { 515 if (error_type == READ_ERROR || error_type == WRITE_ERROR)
437 io_buffer_.clear(); 516 Reset();
438 io_offset_ = 0; 517
439 cumulative_read_buffer_.clear();
440 }
441 PostOnMain(callback_factory_.NewCallback(&CdmFileIOImpl::NotifyClientOfError, 518 PostOnMain(callback_factory_.NewCallback(&CdmFileIOImpl::NotifyClientOfError,
442 error_type)); 519 error_type));
443 } 520 }
444 521
445 void CdmFileIOImpl::NotifyClientOfError(int32_t result, 522 void CdmFileIOImpl::NotifyClientOfError(int32_t result,
446 ErrorType error_type) { 523 ErrorType error_type) {
447 PP_DCHECK(result == PP_OK); 524 PP_DCHECK(result == PP_OK);
448 switch (error_type) { 525 switch (error_type) {
449 case OPEN_ERROR: 526 case OPEN_ERROR:
450 client_->OnOpenComplete(cdm::FileIOClient::kError); 527 client_->OnOpenComplete(cdm::FileIOClient::kError);
(...skipping 10 matching lines...) Expand all
461 case READ_WHILE_IN_USE: 538 case READ_WHILE_IN_USE:
462 client_->OnReadComplete(cdm::FileIOClient::kInUse, NULL, 0); 539 client_->OnReadComplete(cdm::FileIOClient::kInUse, NULL, 0);
463 break; 540 break;
464 case WRITE_WHILE_IN_USE: 541 case WRITE_WHILE_IN_USE:
465 client_->OnWriteComplete(cdm::FileIOClient::kInUse); 542 client_->OnWriteComplete(cdm::FileIOClient::kInUse);
466 break; 543 break;
467 } 544 }
468 } 545 }
469 546
470 } // namespace media 547 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698