Chromium Code Reviews| 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() || 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 Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |