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

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
« no previous file with comments | « media/cdm/ppapi/cdm_file_io_impl.h ('k') | media/cdm/ppapi/cdm_file_io_test.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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() || file_name_str[0] == '_' ||
ddorwin 2014/09/17 23:16:38 nit: Would be nice to have all the independent che
xhwang 2014/09/18 05:58:07 Done.
99 file_name_str.find('/') != std::string::npos ||
91 file_name_str.find('\\') != std::string::npos) { 100 file_name_str.find('\\') != std::string::npos) {
92 CDM_DLOG() << "Invalid file name."; 101 CDM_DLOG() << "Invalid file name.";
102 state_ = STATE_ERROR;
93 OnError(OPEN_ERROR); 103 OnError(OPEN_ERROR);
94 return; 104 return;
95 } 105 }
96 106
97 // pp::FileRef only accepts path that begins with a '/' character. 107 // pp::FileRef only accepts path that begins with a '/' character.
98 file_name_ = '/' + file_name_str; 108 file_name_ = '/' + file_name_str;
99 109
100 if (!AcquireFileLock()) { 110 if (!AcquireFileLock()) {
101 CDM_DLOG() << "File is in use by other cdm::FileIO objects."; 111 CDM_DLOG() << "File is in use by other cdm::FileIO objects.";
102 OnError(OPEN_WHILE_IN_USE); 112 OnError(OPEN_WHILE_IN_USE);
103 return; 113 return;
104 } 114 }
105 115
106 state_ = OPENING_FILE_SYSTEM; 116 state_ = STATE_OPENING_FILE_SYSTEM;
107 OpenFileSystem(); 117 OpenFileSystem();
108 } 118 }
109 119
110 // Call sequence: 120 // Call sequence:
111 // finished 121 // Read() -> OpenFileForRead() -> ReadFile() -> Done.
112 // Read() -> ReadFile() -> OnFileRead() ----------> Done.
113 // ^ |
114 // | not finished |
115 // |--------------|
116 void CdmFileIOImpl::Read() { 122 void CdmFileIOImpl::Read() {
117 CDM_DLOG() << __FUNCTION__; 123 CDM_DLOG() << __FUNCTION__;
118 PP_DCHECK(IsMainThread()); 124 PP_DCHECK(IsMainThread());
119 125
120 if (state_ == READING_FILE || state_ == WRITING_FILE) { 126 if (state_ == STATE_READING || state_ == STATE_WRITING) {
121 CDM_DLOG() << "Read() called during pending read/write."; 127 CDM_DLOG() << "Read() called during pending read/write.";
122 OnError(READ_WHILE_IN_USE); 128 OnError(READ_WHILE_IN_USE);
123 return; 129 return;
124 } 130 }
125 131
126 if (state_ != FILE_OPENED) { 132 if (state_ != STATE_FILE_SYSTEM_OPENED) {
127 CDM_DLOG() << "Read() called in an invalid state."; 133 CDM_DLOG() << "Read() called in an invalid state.";
128 OnError(READ_ERROR); 134 OnError(READ_ERROR);
129 return; 135 return;
130 } 136 }
131 137
138 PP_DCHECK(io_offset_ == 0);
132 PP_DCHECK(io_buffer_.empty()); 139 PP_DCHECK(io_buffer_.empty());
133 PP_DCHECK(cumulative_read_buffer_.empty()); 140 PP_DCHECK(cumulative_read_buffer_.empty());
134
135 io_buffer_.resize(kReadSize); 141 io_buffer_.resize(kReadSize);
136 io_offset_ = 0; 142 io_offset_ = 0;
137 143
138 state_ = READING_FILE; 144 state_ = STATE_READING;
139 ReadFile(); 145 OpenFileForRead();
140 } 146 }
141 147
142 // Call sequence: 148 // Call sequence:
143 // finished 149 // Write() -> OpenTempFileForWrite() -> WriteTempFile() -> RenameTempFile().
144 // Write() -> WriteFile() -> OnFileWritten() ----------> Done. 150 // 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) { 151 void CdmFileIOImpl::Write(const uint8_t* data, uint32_t data_size) {
149 CDM_DLOG() << __FUNCTION__; 152 CDM_DLOG() << __FUNCTION__;
150 PP_DCHECK(IsMainThread()); 153 PP_DCHECK(IsMainThread());
151 154
152 if (state_ == READING_FILE || state_ == WRITING_FILE) { 155 if (state_ == STATE_READING || state_ == STATE_WRITING) {
153 CDM_DLOG() << "Write() called during pending read/write."; 156 CDM_DLOG() << "Write() called during pending read/write.";
154 OnError(WRITE_WHILE_IN_USE); 157 OnError(WRITE_WHILE_IN_USE);
155 return; 158 return;
156 } 159 }
157 160
158 if (state_ != FILE_OPENED) { 161 if (state_ != STATE_FILE_SYSTEM_OPENED) {
159 CDM_DLOG() << "Write() called in an invalid state."; 162 CDM_DLOG() << "Write() called in an invalid state.";
160 OnError(WRITE_ERROR); 163 OnError(WRITE_ERROR);
161 return; 164 return;
162 } 165 }
163 166
164 PP_DCHECK(io_offset_ == 0); 167 PP_DCHECK(io_offset_ == 0);
165 PP_DCHECK(io_buffer_.empty()); 168 PP_DCHECK(io_buffer_.empty());
166 if (data_size > 0) 169 if (data_size > 0)
167 io_buffer_.assign(data, data + data_size); 170 io_buffer_.assign(data, data + data_size);
168 else 171 else
169 PP_DCHECK(!data); 172 PP_DCHECK(!data);
170 173
171 state_ = WRITING_FILE; 174 state_ = STATE_WRITING;
172 175 OpenTempFileForWrite();
173 // Always SetLength() in case |data_size| is less than the file size.
174 SetLength(data_size);
175 } 176 }
176 177
177 void CdmFileIOImpl::Close() { 178 void CdmFileIOImpl::Close() {
178 CDM_DLOG() << __FUNCTION__; 179 CDM_DLOG() << __FUNCTION__;
179 PP_DCHECK(IsMainThread()); 180 PP_DCHECK(IsMainThread());
180 PP_DCHECK(state_ != FILE_CLOSED); 181 PP_DCHECK(state_ != STATE_CLOSED);
181 CloseFile(); 182 Reset();
183 state_ = STATE_CLOSED;
182 ReleaseFileLock(); 184 ReleaseFileLock();
183 // All pending callbacks are canceled since |callback_factory_| is destroyed. 185 // All pending callbacks are canceled since |callback_factory_| is destroyed.
184 delete this; 186 delete this;
185 } 187 }
186 188
187 bool CdmFileIOImpl::SetFileID() { 189 bool CdmFileIOImpl::SetFileID() {
188 PP_DCHECK(file_id_.empty()); 190 PP_DCHECK(file_id_.empty());
189 PP_DCHECK(!file_name_.empty() && file_name_[0] == '/'); 191 PP_DCHECK(!file_name_.empty() && file_name_[0] == '/');
190 192
191 // Not taking ownership of |url_util_dev| (which is a singleton). 193 // Not taking ownership of |url_util_dev| (which is a singleton).
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
230 232
231 if (!file_lock_map_) 233 if (!file_lock_map_)
232 return; 234 return;
233 235
234 FileLockMap::iterator found = file_lock_map_->find(file_id_); 236 FileLockMap::iterator found = file_lock_map_->find(file_id_);
235 if (found != file_lock_map_->end() && found->second) 237 if (found != file_lock_map_->end() && found->second)
236 found->second = false; 238 found->second = false;
237 } 239 }
238 240
239 void CdmFileIOImpl::OpenFileSystem() { 241 void CdmFileIOImpl::OpenFileSystem() {
240 PP_DCHECK(state_ == OPENING_FILE_SYSTEM); 242 PP_DCHECK(state_ == STATE_OPENING_FILE_SYSTEM);
241 243
242 pp::CompletionCallbackWithOutput<pp::FileSystem> cb = 244 pp::CompletionCallbackWithOutput<pp::FileSystem> cb =
243 callback_factory_.NewCallbackWithOutput( 245 callback_factory_.NewCallbackWithOutput(
244 &CdmFileIOImpl::OnFileSystemOpened); 246 &CdmFileIOImpl::OnFileSystemOpened);
245 isolated_file_system_ = pp::IsolatedFileSystemPrivate( 247 isolated_file_system_ = pp::IsolatedFileSystemPrivate(
246 pp_instance_handle_, PP_ISOLATEDFILESYSTEMTYPE_PRIVATE_PLUGINPRIVATE); 248 pp_instance_handle_, PP_ISOLATEDFILESYSTEMTYPE_PRIVATE_PLUGINPRIVATE);
247 249
248 CHECK_PP_OK_COMPLETIONPENDING(isolated_file_system_.Open(cb), OPEN_ERROR); 250 CHECK_PP_OK_COMPLETIONPENDING(isolated_file_system_.Open(cb), OPEN_ERROR);
249 } 251 }
250 252
251 void CdmFileIOImpl::OnFileSystemOpened(int32_t result, 253 void CdmFileIOImpl::OnFileSystemOpened(int32_t result,
252 pp::FileSystem file_system) { 254 pp::FileSystem file_system) {
253 PP_DCHECK(IsMainThread()); 255 PP_DCHECK(IsMainThread());
254 PP_DCHECK(state_ == OPENING_FILE_SYSTEM); 256 PP_DCHECK(state_ == STATE_OPENING_FILE_SYSTEM);
255 257
256 if (result != PP_OK) { 258 if (result != PP_OK) {
257 CDM_DLOG() << "File system open failed asynchronously."; 259 CDM_DLOG() << "File system open failed asynchronously.";
258 ReleaseFileLock(); 260 ReleaseFileLock();
261 state_ = STATE_ERROR;
259 OnError(OPEN_ERROR); 262 OnError(OPEN_ERROR);
260 return; 263 return;
261 } 264 }
262 265
263 file_system_ = file_system; 266 file_system_ = file_system;
264 state_ = OPENING_FILE; 267
265 OpenFile(); 268 state_ = STATE_FILE_SYSTEM_OPENED;
269 client_->OnOpenComplete(cdm::FileIOClient::kSuccess);
266 } 270 }
267 271
268 void CdmFileIOImpl::OpenFile() { 272 void CdmFileIOImpl::OpenFileForRead() {
269 PP_DCHECK(state_ == OPENING_FILE); 273 PP_DCHECK(state_ == STATE_READING);
270 274
275 PP_DCHECK(file_io_.is_null());
276 PP_DCHECK(file_ref_.is_null());
271 file_io_ = pp::FileIO(pp_instance_handle_); 277 file_io_ = pp::FileIO(pp_instance_handle_);
272 file_ref_ = pp::FileRef(file_system_, file_name_.c_str()); 278 file_ref_ = pp::FileRef(file_system_, file_name_.c_str());
273 int32_t file_open_flag = PP_FILEOPENFLAG_READ | 279
274 PP_FILEOPENFLAG_WRITE | 280 // Open file for read. If file doesn't exist, PP_ERROR_FILENOTFOUND will be
275 PP_FILEOPENFLAG_CREATE; 281 // returned.
282 int32_t file_open_flag = PP_FILEOPENFLAG_READ;
283
276 pp::CompletionCallback cb = 284 pp::CompletionCallback cb =
277 callback_factory_.NewCallback(&CdmFileIOImpl::OnFileOpened); 285 callback_factory_.NewCallback(&CdmFileIOImpl::OnFileOpenedForRead);
278 CHECK_PP_OK_COMPLETIONPENDING(file_io_.Open(file_ref_, file_open_flag, cb), 286 CHECK_PP_OK_COMPLETIONPENDING(file_io_.Open(file_ref_, file_open_flag, cb),
279 OPEN_ERROR); 287 READ_ERROR);
280 } 288 }
281 289
282 void CdmFileIOImpl::OnFileOpened(int32_t result) { 290 void CdmFileIOImpl::OnFileOpenedForRead(int32_t result) {
291 CDM_DLOG() << __FUNCTION__ << ": " << result;
283 PP_DCHECK(IsMainThread()); 292 PP_DCHECK(IsMainThread());
284 PP_DCHECK(state_ == OPENING_FILE); 293 PP_DCHECK(state_ == STATE_READING);
285 294
286 if (result != PP_OK) { 295 if (result != PP_OK && result != PP_ERROR_FILENOTFOUND) {
ddorwin 2014/09/17 23:16:38 Avoid this by checking the specific error first?
xhwang 2014/09/18 05:58:07 I'd like to handle "error" cases first. PP_ERROR_F
287 CDM_DLOG() << "File open failed."; 296 CDM_DLOG() << "File open failed.";
288 ReleaseFileLock(); 297 state_ = STATE_ERROR;
ddorwin 2014/09/17 23:16:38 Who is releasing the lock now? In fact, it's not c
xhwang 2014/09/18 05:58:07 The FileIO doc says that when a FileIO is opened,
289 OnError(OPEN_ERROR); 298 OnError(OPEN_ERROR);
290 return; 299 return;
291 } 300 }
292 301
293 state_ = FILE_OPENED; 302 // File doesn't exist.
294 client_->OnOpenComplete(cdm::FileIOClient::kSuccess); 303 if (result == PP_ERROR_FILENOTFOUND) {
304 Reset();
305 state_ = STATE_FILE_SYSTEM_OPENED;
306 client_->OnReadComplete(cdm::FileIOClient::kSuccess, NULL, 0);
307 return;
308 }
309
310 ReadFile();
295 } 311 }
296 312
313 // Call sequence:
314 // fully read
315 // ReadFile() ---> OnFileRead() ------------> Done.
316 // ^ |
317 // | partially read |
318 // |----------------|
297 void CdmFileIOImpl::ReadFile() { 319 void CdmFileIOImpl::ReadFile() {
298 PP_DCHECK(state_ == READING_FILE); 320 PP_DCHECK(state_ == STATE_READING);
299 PP_DCHECK(!io_buffer_.empty()); 321 PP_DCHECK(!io_buffer_.empty());
300 322
301 pp::CompletionCallback cb = 323 pp::CompletionCallback cb =
302 callback_factory_.NewCallback(&CdmFileIOImpl::OnFileRead); 324 callback_factory_.NewCallback(&CdmFileIOImpl::OnFileRead);
303 CHECK_PP_OK_COMPLETIONPENDING( 325 CHECK_PP_OK_COMPLETIONPENDING(
304 file_io_.Read(io_offset_, &io_buffer_[0], io_buffer_.size(), cb), 326 file_io_.Read(io_offset_, &io_buffer_[0], io_buffer_.size(), cb),
305 READ_ERROR); 327 READ_ERROR);
306 } 328 }
307 329
308 void CdmFileIOImpl::OnFileRead(int32_t bytes_read) { 330 void CdmFileIOImpl::OnFileRead(int32_t bytes_read) {
309 CDM_DLOG() << __FUNCTION__ << ": " << bytes_read; 331 CDM_DLOG() << __FUNCTION__ << ": " << bytes_read;
310 PP_DCHECK(IsMainThread()); 332 PP_DCHECK(IsMainThread());
311 PP_DCHECK(state_ == READING_FILE); 333 PP_DCHECK(state_ == STATE_READING);
312 334
313 // 0 |bytes_read| indicates end-of-file reached. 335 // 0 |bytes_read| indicates end-of-file reached.
314 if (bytes_read < PP_OK) { 336 if (bytes_read < PP_OK) {
315 CDM_DLOG() << "Read file failed."; 337 CDM_DLOG() << "Read file failed.";
338 state_ = STATE_ERROR;
316 OnError(READ_ERROR); 339 OnError(READ_ERROR);
317 return; 340 return;
318 } 341 }
319 342
320 PP_DCHECK(static_cast<size_t>(bytes_read) <= io_buffer_.size()); 343 PP_DCHECK(static_cast<size_t>(bytes_read) <= io_buffer_.size());
321 // Append |bytes_read| in |io_buffer_| to |cumulative_read_buffer_|. 344 // Append |bytes_read| in |io_buffer_| to |cumulative_read_buffer_|.
322 cumulative_read_buffer_.insert(cumulative_read_buffer_.end(), 345 cumulative_read_buffer_.insert(cumulative_read_buffer_.end(),
323 io_buffer_.begin(), 346 io_buffer_.begin(),
324 io_buffer_.begin() + bytes_read); 347 io_buffer_.begin() + bytes_read);
325 io_offset_ += bytes_read; 348 io_offset_ += bytes_read;
326 349
327 // Not received end-of-file yet. 350 // Not received end-of-file yet. Keep reading.
328 if (bytes_read > 0) { 351 if (bytes_read > 0) {
329 ReadFile(); 352 ReadFile();
330 return; 353 return;
331 } 354 }
332 355
333 // We hit end-of-file. Return read data to the client. 356 // We hit end-of-file. Return read data to the client.
334 io_buffer_.clear(); 357
335 io_offset_ = 0;
336 // Clear |cumulative_read_buffer_| in case OnReadComplete() calls Read() or 358 // Clear |cumulative_read_buffer_| in case OnReadComplete() calls Read() or
337 // Write(). 359 // Write().
338 std::vector<char> local_buffer; 360 std::vector<char> local_buffer;
339 std::swap(cumulative_read_buffer_, local_buffer); 361 std::swap(cumulative_read_buffer_, local_buffer);
340 362
341 state_ = FILE_OPENED;
342 const uint8_t* data = local_buffer.empty() ? 363 const uint8_t* data = local_buffer.empty() ?
343 NULL : reinterpret_cast<const uint8_t*>(&local_buffer[0]); 364 NULL : reinterpret_cast<const uint8_t*>(&local_buffer[0]);
344 365
345 // Call this before OnReadComplete() so that we always have the latest file 366 // Call this before OnReadComplete() so that we always have the latest file
346 // size before CDM fires errors. 367 // size before CDM fires errors.
347 if (!first_file_read_reported_) { 368 if (!first_file_read_reported_) {
348 first_file_read_cb_.Run(local_buffer.size()); 369 first_file_read_cb_.Run(local_buffer.size());
349 first_file_read_reported_ = true; 370 first_file_read_reported_ = true;
350 } 371 }
351 372
373 Reset();
374
375 state_ = STATE_FILE_SYSTEM_OPENED;
352 client_->OnReadComplete( 376 client_->OnReadComplete(
353 cdm::FileIOClient::kSuccess, data, local_buffer.size()); 377 cdm::FileIOClient::kSuccess, data, local_buffer.size());
354 } 378 }
355 379
356 void CdmFileIOImpl::SetLength(uint32_t length) { 380 void CdmFileIOImpl::OpenTempFileForWrite() {
357 PP_DCHECK(state_ == WRITING_FILE); 381 PP_DCHECK(state_ == STATE_WRITING);
382
383 PP_DCHECK(file_name_.size() > 1 && file_name_[0] == '/');
384 // Temporary file name format: /_<requested_file_name>
385 std::string temp_file_name = "/_" + file_name_.substr(1);
386
387 PP_DCHECK(file_io_.is_null());
388 PP_DCHECK(file_ref_.is_null());
389 file_io_ = pp::FileIO(pp_instance_handle_);
390 file_ref_ = pp::FileRef(file_system_, temp_file_name.c_str());
391
392 // Create the file if it doesn't exist. Truncate the file to length 0 if it
393 // exists.
394 // TODO(xhwang): Find a good way to report to UMA cases where the temporary
ddorwin 2014/09/17 23:16:38 Thanks. Would the following work (separate CL is f
xhwang 2014/09/18 05:58:07 That'll work, but we are less efficient. As I said
395 // file already exists (due to previous interruption or failure).
396 int32_t file_open_flag = PP_FILEOPENFLAG_WRITE |
397 PP_FILEOPENFLAG_TRUNCATE |
398 PP_FILEOPENFLAG_CREATE;
358 399
359 pp::CompletionCallback cb = 400 pp::CompletionCallback cb =
360 callback_factory_.NewCallback(&CdmFileIOImpl::OnLengthSet); 401 callback_factory_.NewCallback(&CdmFileIOImpl::OnTempFileOpenedForWrite);
361 CHECK_PP_OK_COMPLETIONPENDING(file_io_.SetLength(length, cb), WRITE_ERROR); 402 CHECK_PP_OK_COMPLETIONPENDING(
403 file_io_.Open(file_ref_, file_open_flag, cb), WRITE_ERROR);
362 } 404 }
363 405
364 void CdmFileIOImpl::OnLengthSet(int32_t result) { 406 void CdmFileIOImpl::OnTempFileOpenedForWrite(int32_t result) {
365 CDM_DLOG() << __FUNCTION__ << ": " << result; 407 CDM_DLOG() << __FUNCTION__ << ": " << result;
366 PP_DCHECK(IsMainThread()); 408 PP_DCHECK(IsMainThread());
367 PP_DCHECK(state_ == WRITING_FILE); 409 PP_DCHECK(state_ == STATE_WRITING);
368 410
369 if (result != PP_OK) { 411 if (result != PP_OK) {
370 CDM_DLOG() << "File SetLength failed."; 412 CDM_DLOG() << "Open temporary file failed.";
413 state_ = STATE_ERROR;
371 OnError(WRITE_ERROR); 414 OnError(WRITE_ERROR);
372 return; 415 return;
373 } 416 }
374 417
418 // We were told to write 0 bytes (to clear the file). In this case, there's
419 // no need to write anything.
375 if (io_buffer_.empty()) { 420 if (io_buffer_.empty()) {
376 state_ = FILE_OPENED; 421 RenameTempFile();
377 client_->OnWriteComplete(cdm::FileIOClient::kSuccess);
378 return; 422 return;
379 } 423 }
380 424
381 WriteFile(); 425 PP_DCHECK(io_offset_ == 0);
426 io_offset_ = 0;
427 WriteTempFile();
382 } 428 }
383 429
384 void CdmFileIOImpl::WriteFile() { 430 // Call sequence:
385 PP_DCHECK(state_ == WRITING_FILE); 431 // fully written
432 // WriteTempFile() -> OnTempFileWritten() ---------------> RenameTempFile().
433 // ^ |
434 // | partially written |
435 // |---------------------|
436 void CdmFileIOImpl::WriteTempFile() {
437 PP_DCHECK(state_ == STATE_WRITING);
386 PP_DCHECK(io_offset_ < io_buffer_.size()); 438 PP_DCHECK(io_offset_ < io_buffer_.size());
387 439
388 pp::CompletionCallback cb = 440 pp::CompletionCallback cb =
389 callback_factory_.NewCallback(&CdmFileIOImpl::OnFileWritten); 441 callback_factory_.NewCallback(&CdmFileIOImpl::OnTempFileWritten);
390 CHECK_PP_OK_COMPLETIONPENDING(file_io_.Write(io_offset_, 442 CHECK_PP_OK_COMPLETIONPENDING(file_io_.Write(io_offset_,
391 &io_buffer_[io_offset_], 443 &io_buffer_[io_offset_],
392 io_buffer_.size() - io_offset_, 444 io_buffer_.size() - io_offset_,
393 cb), 445 cb),
394 WRITE_ERROR); 446 WRITE_ERROR);
395 } 447 }
396 448
397 void CdmFileIOImpl::OnFileWritten(int32_t bytes_written) { 449 void CdmFileIOImpl::OnTempFileWritten(int32_t bytes_written) {
398 CDM_DLOG() << __FUNCTION__ << ": " << bytes_written; 450 CDM_DLOG() << __FUNCTION__ << ": " << bytes_written;
399 PP_DCHECK(IsMainThread()); 451 PP_DCHECK(IsMainThread());
400 PP_DCHECK(state_ == WRITING_FILE); 452 PP_DCHECK(state_ == STATE_WRITING);
401 453
402 if (bytes_written <= PP_OK) { 454 if (bytes_written <= PP_OK) {
403 CDM_DLOG() << "Write file failed."; 455 CDM_DLOG() << "Write temporary file failed.";
404 OnError(READ_ERROR); 456 state_ = STATE_ERROR;
457 OnError(WRITE_ERROR);
405 return; 458 return;
406 } 459 }
407 460
408 io_offset_ += bytes_written; 461 io_offset_ += bytes_written;
409 PP_DCHECK(io_offset_ <= io_buffer_.size()); 462 PP_DCHECK(io_offset_ <= io_buffer_.size());
410 463
411 if (io_offset_ < io_buffer_.size()) { 464 if (io_offset_ < io_buffer_.size()) {
412 WriteFile(); 465 WriteTempFile();
413 return; 466 return;
414 } 467 }
415 468
416 io_buffer_.clear(); 469 // All data written. Now rename the temporary file to the real file.
417 io_offset_ = 0; 470 RenameTempFile();
418 state_ = FILE_OPENED; 471 }
472
473 void CdmFileIOImpl::RenameTempFile() {
474 PP_DCHECK(state_ == STATE_WRITING);
475
476 pp::CompletionCallback cb =
477 callback_factory_.NewCallback(&CdmFileIOImpl::OnTempFileRenamed);
478 CHECK_PP_OK_COMPLETIONPENDING(
479 file_ref_.Rename(pp::FileRef(file_system_, file_name_.c_str()), cb),
480 WRITE_ERROR);
481 }
482
483 void CdmFileIOImpl::OnTempFileRenamed(int32_t result) {
484 CDM_DLOG() << __FUNCTION__ << ": " << result;
485 PP_DCHECK(IsMainThread());
486 PP_DCHECK(state_ == STATE_WRITING);
487
488 if (result != PP_OK) {
489 CDM_DLOG() << "Rename temporary file failed.";
490 state_ = STATE_ERROR;
491 OnError(WRITE_ERROR);
492 return;
493 }
494
495 Reset();
496
497 state_ = STATE_FILE_SYSTEM_OPENED;
419 client_->OnWriteComplete(cdm::FileIOClient::kSuccess); 498 client_->OnWriteComplete(cdm::FileIOClient::kSuccess);
420 } 499 }
421 500
422 void CdmFileIOImpl::CloseFile() { 501 void CdmFileIOImpl::Reset() {
423 PP_DCHECK(IsMainThread()); 502 PP_DCHECK(IsMainThread());
424
425 state_ = FILE_CLOSED;
426
427 file_io_.Close();
428 io_buffer_.clear(); 503 io_buffer_.clear();
429 io_offset_ = 0; 504 io_offset_ = 0;
430 cumulative_read_buffer_.clear(); 505 cumulative_read_buffer_.clear();
506 file_io_.Close();
507 file_io_ = pp::FileIO();
508 file_ref_ = pp::FileRef();
431 } 509 }
432 510
433 void CdmFileIOImpl::OnError(ErrorType error_type) { 511 void CdmFileIOImpl::OnError(ErrorType error_type) {
434 // For *_WHILE_IN_USE errors, do not reset these values. Otherwise, the 512 // For *_WHILE_IN_USE errors, do not reset these values. Otherwise, the
435 // existing read/write operation will fail. 513 // existing read/write operation will fail.
436 if (error_type == READ_ERROR || error_type == WRITE_ERROR) { 514 if (error_type == READ_ERROR || error_type == WRITE_ERROR)
437 io_buffer_.clear(); 515 Reset();
438 io_offset_ = 0; 516
439 cumulative_read_buffer_.clear();
440 }
441 PostOnMain(callback_factory_.NewCallback(&CdmFileIOImpl::NotifyClientOfError, 517 PostOnMain(callback_factory_.NewCallback(&CdmFileIOImpl::NotifyClientOfError,
442 error_type)); 518 error_type));
443 } 519 }
444 520
445 void CdmFileIOImpl::NotifyClientOfError(int32_t result, 521 void CdmFileIOImpl::NotifyClientOfError(int32_t result,
446 ErrorType error_type) { 522 ErrorType error_type) {
447 PP_DCHECK(result == PP_OK); 523 PP_DCHECK(result == PP_OK);
448 switch (error_type) { 524 switch (error_type) {
449 case OPEN_ERROR: 525 case OPEN_ERROR:
450 client_->OnOpenComplete(cdm::FileIOClient::kError); 526 client_->OnOpenComplete(cdm::FileIOClient::kError);
(...skipping 10 matching lines...) Expand all
461 case READ_WHILE_IN_USE: 537 case READ_WHILE_IN_USE:
462 client_->OnReadComplete(cdm::FileIOClient::kInUse, NULL, 0); 538 client_->OnReadComplete(cdm::FileIOClient::kInUse, NULL, 0);
463 break; 539 break;
464 case WRITE_WHILE_IN_USE: 540 case WRITE_WHILE_IN_USE:
465 client_->OnWriteComplete(cdm::FileIOClient::kInUse); 541 client_->OnWriteComplete(cdm::FileIOClient::kInUse);
466 break; 542 break;
467 } 543 }
468 } 544 }
469 545
470 } // namespace media 546 } // namespace media
OLDNEW
« no previous file with comments | « media/cdm/ppapi/cdm_file_io_impl.h ('k') | media/cdm/ppapi/cdm_file_io_test.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698