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 3// found in the LICENSE file. 4 5#ifndef MEDIA_CDM_PPAPI_CDM_FILE_IO_IMPL_H_ 6#define MEDIA_CDM_PPAPI_CDM_FILE_IO_IMPL_H_ 7 8#include <algorithm> 9#include <string> 10#include <vector> 11 12#include "base/basictypes.h" 13#include "media/cdm/ppapi/api/content_decryption_module.h" 14#include "ppapi/c/ppb_file_io.h" 15#include "ppapi/cpp/file_io.h" 16#include "ppapi/cpp/file_ref.h" 17#include "ppapi/cpp/instance.h" 18#include "ppapi/cpp/module.h" 19#include "ppapi/cpp/private/isolated_file_system_private.h" 20#include "ppapi/utility/completion_callback_factory.h" 21 22namespace media { 23 24// Due to PPAPI limitations, all functions must be called on the main thread. 25class CdmFileIOImpl : public cdm::FileIO { 26 public: 27 // A class that helps release |file_lock_map_|. 28 // There should be only one instance of ResourceTracker in a process. Also, 29 // ResourceTracker should outlive all CdmFileIOImpl instances. 30 class ResourceTracker { 31 public: 32 ResourceTracker(); 33 ~ResourceTracker(); 34 private: 35 DISALLOW_COPY_AND_ASSIGN(ResourceTracker); 36 }; 37 38 CdmFileIOImpl(cdm::FileIOClient* client, PP_Instance pp_instance); 39 40 // cdm::FileIO implementation. 41 virtual void Open(const char* file_name, uint32_t file_name_size) OVERRIDE; 42 virtual void Read() OVERRIDE; 43 virtual void Write(const uint8_t* data, uint32_t data_size) OVERRIDE; 44 virtual void Close() OVERRIDE; 45 46 private: 47 enum State { 48 FILE_UNOPENED, 49 OPENING_FILE_SYSTEM, 50 OPENING_FILE, 51 FILE_OPENED, 52 READING_FILE, 53 WRITING_FILE, 54 FILE_CLOSED 55 }; 56 57 enum ErrorType { 58 OPEN_WHILE_IN_USE, 59 READ_WHILE_IN_USE, 60 WRITE_WHILE_IN_USE, 61 OPEN_ERROR, 62 READ_ERROR, 63 WRITE_ERROR 64 }; 65 66 // Always use Close() to release |this| object. 67 virtual ~CdmFileIOImpl(); 68 69 // |file_id_| -> |is_file_lock_acquired_| map. 70 // Design detail: 71 // - We never erase an entry from this map. 72 // - Pros: When the same file is read or written repeatedly, we don't need to 73 // insert/erase the entry repeatedly, which is expensive. 74 // - Cons: If there are a lot of one-off files used, this map will be 75 // unnecessarily large. But this should be a rare case. 76 // - Ideally we could use unordered_map for this. But unordered_set is only 77 // available in C++11. 78 typedef std::map<std::string, bool> FileLockMap; 79 80 // File lock map shared by all CdmFileIOImpl objects to prevent read/write 81 // race. A CdmFileIOImpl object tries to acquire a lock before opening a 82 // file. If the file open failed, the lock is released. Otherwise, the 83 // CdmFileIOImpl object holds the lock until Close() is called. 84 // TODO(xhwang): Investigate the following cases and make sure we are good: 85 // - This assumes all CDM instances run in the same process for a given file 86 // system. 87 // - When multiple CDM instances are running in different profiles (e.g. 88 // normal/incognito window, multiple profiles), we may be overlocking. 89 static FileLockMap* file_lock_map_; 90 91 // Sets |file_id_|. Returns false if |file_id_| cannot be set (e.g. origin URL 92 // cannot be fetched). 93 bool SetFileID(); 94 95 // Acquires the file lock. Returns true if the lock is successfully acquired. 96 // After the lock is acquired, other cdm::FileIO objects in the same process 97 // and in the same origin will get kInUse when trying to open the same file. 98 bool AcquireFileLock(); 99 100 // Releases the file lock so that the file can be opened by other cdm::FileIO 101 // objects. 102 void ReleaseFileLock(); 103 104 void OpenFileSystem(); 105 void OnFileSystemOpened(int32_t result, pp::FileSystem file_system); 106 void OpenFile(); 107 void OnFileOpened(int32_t result); 108 void ReadFile(); 109 void OnFileRead(int32_t bytes_read); 110 void SetLength(uint32_t length); 111 void OnLengthSet(int32_t result); 112 void WriteFile(); 113 void OnFileWritten(int32_t bytes_written); 114 115 void CloseFile(); 116 117 // Calls client_->OnXxxxComplete with kError asynchronously. In some cases we 118 // could actually call them synchronously, but since these errors shouldn't 119 // happen in normal cases, we are not optimizing such cases. 120 void OnError(ErrorType error_type); 121 122 // Callback to notify client of error asynchronously. 123 void NotifyClientOfError(int32_t result, ErrorType error_type); 124 125 State state_; 126 127 // Non-owning pointer. 128 cdm::FileIOClient* const client_; 129 130 const pp::InstanceHandle pp_instance_handle_; 131 132 std::string file_name_; 133 134 // A string ID that uniquely identifies a file in the user's profile. 135 // It consists of the origin of the document URL (including scheme, host and 136 // port, delimited by colons) and the |file_name_|. 137 // For example: http:example.com:8080/foo_file.txt 138 std::string file_id_; 139 140 pp::IsolatedFileSystemPrivate isolated_file_system_; 141 pp::FileSystem file_system_; 142 pp::FileIO file_io_; 143 pp::FileRef file_ref_; 144 145 pp::CompletionCallbackFactory<CdmFileIOImpl> callback_factory_; 146 147 // A temporary buffer to hold (partial) data to write or the data that has 148 // been read. The size of |io_buffer_| is always "bytes to write" or "bytes to 149 // read". Use "char" instead of "unit8_t" because PPB_FileIO uses char* for 150 // binary data read and write. 151 std::vector<char> io_buffer_; 152 153 // Offset into the file for reading/writing data. When writing data to the 154 // file, this is also the offset to the |io_buffer_|. 155 size_t io_offset_; 156 157 // Buffer to hold all read data requested. This buffer is passed to |client_| 158 // when read completes. 159 std::vector<char> cumulative_read_buffer_; 160 161 DISALLOW_COPY_AND_ASSIGN(CdmFileIOImpl); 162}; 163 164} // namespace media 165 166#endif // MEDIA_CDM_PPAPI_CDM_FILE_IO_IMPL_H_ 167