Upstreaming browser/ui/uikit_ui_util from iOS.
[chromium-blink-merge.git] / media / cdm / ppapi / cdm_file_io_impl.h
blob8e7a88b1a20a68c27721eaafc50f1043089ca3c6
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.
5 #ifndef MEDIA_CDM_PPAPI_CDM_FILE_IO_IMPL_H_
6 #define MEDIA_CDM_PPAPI_CDM_FILE_IO_IMPL_H_
8 #include <algorithm>
9 #include <string>
10 #include <vector>
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"
22 namespace media {
24 // Due to PPAPI limitations, all functions must be called on the main thread.
26 // Implementation notes about states:
27 // 1, When a method is called in an invalid state (e.g. Read() before Open() is
28 // called, Write() before Open() finishes or Open() after Open()), kError
29 // will be returned. The state of |this| will not change.
30 // 2, When the file is opened by another CDM instance, or when we call Read()/
31 // Write() during a pending Read()/Write(), kInUse will be returned. The
32 // state of |this| will not change.
33 // 3, When a pepper operation failed (either synchronously or asynchronously),
34 // kError will be returned. The state of |this| will be set to ERROR.
35 // 4. Any operation in ERROR state will end up with kError.
36 class CdmFileIOImpl : public cdm::FileIO {
37 public:
38 // A class that helps release |file_lock_map_|.
39 // There should be only one instance of ResourceTracker in a process. Also,
40 // ResourceTracker should outlive all CdmFileIOImpl instances.
41 class ResourceTracker {
42 public:
43 ResourceTracker();
44 ~ResourceTracker();
45 private:
46 DISALLOW_COPY_AND_ASSIGN(ResourceTracker);
49 // After the first successful file read, call |first_file_read_cb| to report
50 // the file size. |first_file_read_cb| takes one parameter: the file size in
51 // bytes.
52 CdmFileIOImpl(cdm::FileIOClient* client,
53 PP_Instance pp_instance,
54 const pp::CompletionCallback& first_file_read_cb);
56 // cdm::FileIO implementation.
57 void Open(const char* file_name, uint32_t file_name_size) override;
58 void Read() override;
59 void Write(const uint8_t* data, uint32_t data_size) override;
60 void Close() override;
62 private:
63 // TODO(xhwang): Introduce more detailed states for UMA logging if needed.
64 enum State {
65 STATE_UNOPENED,
66 STATE_OPENING_FILE_SYSTEM,
67 STATE_FILE_SYSTEM_OPENED,
68 STATE_READING,
69 STATE_WRITING,
70 STATE_CLOSED,
71 STATE_ERROR
74 enum ErrorType {
75 OPEN_WHILE_IN_USE,
76 READ_WHILE_IN_USE,
77 WRITE_WHILE_IN_USE,
78 OPEN_ERROR,
79 READ_ERROR,
80 WRITE_ERROR
83 // Always use Close() to release |this| object.
84 virtual ~CdmFileIOImpl();
86 // |file_id_| -> |is_file_lock_acquired_| map.
87 // Design detail:
88 // - We never erase an entry from this map.
89 // - Pros: When the same file is read or written repeatedly, we don't need to
90 // insert/erase the entry repeatedly, which is expensive.
91 // - Cons: If there are a lot of one-off files used, this map will be
92 // unnecessarily large. But this should be a rare case.
93 // - Ideally we could use unordered_map for this. But unordered_set is only
94 // available in C++11.
95 typedef std::map<std::string, bool> FileLockMap;
97 // File lock map shared by all CdmFileIOImpl objects to prevent read/write
98 // race. A CdmFileIOImpl object tries to acquire a lock before opening a
99 // file. If the file open failed, the lock is released. Otherwise, the
100 // CdmFileIOImpl object holds the lock until Close() is called.
101 // TODO(xhwang): Investigate the following cases and make sure we are good:
102 // - This assumes all CDM instances run in the same process for a given file
103 // system.
104 // - When multiple CDM instances are running in different profiles (e.g.
105 // normal/incognito window, multiple profiles), we may be overlocking.
106 static FileLockMap* file_lock_map_;
108 // Sets |file_id_|. Returns false if |file_id_| cannot be set (e.g. origin URL
109 // cannot be fetched).
110 bool SetFileID();
112 // Acquires the file lock. Returns true if the lock is successfully acquired.
113 // After the lock is acquired, other cdm::FileIO objects in the same process
114 // and in the same origin will get kInUse when trying to open the same file.
115 bool AcquireFileLock();
117 // Releases the file lock so that the file can be opened by other cdm::FileIO
118 // objects.
119 void ReleaseFileLock();
121 // Helper functions for Open().
122 void OpenFileSystem();
123 void OnFileSystemOpened(int32_t result, pp::FileSystem file_system);
125 // Helper functions for Read().
126 void OpenFileForRead();
127 void OnFileOpenedForRead(int32_t result);
128 void ReadFile();
129 void OnFileRead(int32_t bytes_read);
131 // Helper functions for Write(). We always write data to a temporary file,
132 // then rename the temporary file to the target file. This can prevent data
133 // corruption if |this| is Close()'ed while waiting for writing to complete.
134 // However, if Close() is called after OpenTempFileForWrite() but before
135 // RenameTempFile(), we may still end up with an empty, partially written or
136 // fully written temporary file in the file system. This temporary file will
137 // be truncated next time OpenTempFileForWrite() is called.
139 void OpenTempFileForWrite();
140 void OnTempFileOpenedForWrite(int32_t result);
141 void WriteTempFile();
142 void OnTempFileWritten(int32_t bytes_written);
143 // Note: pp::FileRef::Rename() actually does a "move": if the target file
144 // exists, Rename() will succeed and the target file will be overwritten.
145 // See PepperInternalFileRefBackend::Rename() for implementation detail.
146 void RenameTempFile();
147 void OnTempFileRenamed(int32_t result);
149 // Reset |this| to a clean state.
150 void Reset();
152 // For real open/read/write errors, Reset() and set the |state_| to ERROR.
153 // Calls client_->OnXxxxComplete with kError or kInUse asynchronously. In some
154 // cases we could actually call them synchronously, but since these errors
155 // shouldn't happen in normal cases, we are not optimizing such cases.
156 void OnError(ErrorType error_type);
158 // Callback to notify client of error asynchronously.
159 void NotifyClientOfError(int32_t result, ErrorType error_type);
161 State state_;
163 // Non-owning pointer.
164 cdm::FileIOClient* const client_;
166 const pp::InstanceHandle pp_instance_handle_;
168 // Format: /<requested_file_name>
169 std::string file_name_;
171 // A string ID that uniquely identifies a file in the user's profile.
172 // It consists of the origin of the document URL (including scheme, host and
173 // port, delimited by colons) and the |file_name_|.
174 // For example: http:example.com:8080/foo_file.txt
175 std::string file_id_;
177 pp::IsolatedFileSystemPrivate isolated_file_system_;
178 pp::FileSystem file_system_;
180 // Shared between read and write. During read, |file_ref_| refers to the real
181 // file to read data from. During write, it refers to the temporary file to
182 // write data into.
183 pp::FileIO file_io_;
184 pp::FileRef file_ref_;
186 // A temporary buffer to hold (partial) data to write or the data that has
187 // been read. The size of |io_buffer_| is always "bytes to write" or "bytes to
188 // read". Use "char" instead of "unit8_t" because PPB_FileIO uses char* for
189 // binary data read and write.
190 std::vector<char> io_buffer_;
192 // Offset into the file for reading/writing data. When writing data to the
193 // file, this is also the offset to the |io_buffer_|.
194 size_t io_offset_;
196 // Buffer to hold all read data requested. This buffer is passed to |client_|
197 // when read completes.
198 std::vector<char> cumulative_read_buffer_;
200 bool first_file_read_reported_;
202 // Callback to report the file size in bytes after the first successful read.
203 pp::CompletionCallback first_file_read_cb_;
205 pp::CompletionCallbackFactory<CdmFileIOImpl> callback_factory_;
207 DISALLOW_COPY_AND_ASSIGN(CdmFileIOImpl);
210 } // namespace media
212 #endif // MEDIA_CDM_PPAPI_CDM_FILE_IO_IMPL_H_