OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |