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