• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2012 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 CHROME_BROWSER_MEDIA_GALLERIES_LINUX_MTP_DEVICE_DELEGATE_IMPL_LINUX_H_
6 #define CHROME_BROWSER_MEDIA_GALLERIES_LINUX_MTP_DEVICE_DELEGATE_IMPL_LINUX_H_
7 
8 #include <deque>
9 #include <map>
10 #include <set>
11 #include <string>
12 
13 #include "base/callback.h"
14 #include "base/containers/scoped_ptr_hash_map.h"
15 #include "base/files/file_path.h"
16 #include "base/location.h"
17 #include "base/memory/scoped_ptr.h"
18 #include "base/memory/weak_ptr.h"
19 #include "chrome/browser/media_galleries/fileapi/mtp_device_async_delegate.h"
20 #include "content/public/browser/browser_thread.h"
21 #include "storage/browser/fileapi/async_file_util.h"
22 
23 struct SnapshotRequestInfo;
24 
25 // MTPDeviceDelegateImplLinux communicates with the media transfer protocol
26 // (MTP) device to complete file system operations. These operations are
27 // performed asynchronously. Instantiate this class per MTP device storage.
28 // MTPDeviceDelegateImplLinux lives on the IO thread.
29 // MTPDeviceDelegateImplLinux does a call-and-reply to the UI thread
30 // to dispatch the requests to MediaTransferProtocolManager.
31 class MTPDeviceDelegateImplLinux : public MTPDeviceAsyncDelegate {
32  private:
33   friend void CreateMTPDeviceAsyncDelegate(
34       const std::string&,
35       const CreateMTPDeviceAsyncDelegateCallback&);
36 
37   enum InitializationState {
38     UNINITIALIZED = 0,
39     PENDING_INIT,
40     INITIALIZED
41   };
42 
43   // Used to represent pending task details.
44   struct PendingTaskInfo {
45     PendingTaskInfo(const base::FilePath& path,
46                     content::BrowserThread::ID thread_id,
47                     const tracked_objects::Location& location,
48                     const base::Closure& task);
49     ~PendingTaskInfo();
50 
51     base::FilePath path;
52     base::FilePath cached_path;
53     const content::BrowserThread::ID thread_id;
54     const tracked_objects::Location location;
55     const base::Closure task;
56   };
57 
58   class MTPFileNode;
59 
60   // Maps file ids to file nodes.
61   typedef std::map<uint32, MTPFileNode*> FileIdToMTPFileNodeMap;
62 
63   // Maps file paths to file info.
64   typedef std::map<base::FilePath, storage::DirectoryEntry> FileInfoCache;
65 
66   // Should only be called by CreateMTPDeviceAsyncDelegate() factory call.
67   // Defer the device initializations until the first file operation request.
68   // Do all the initializations in EnsureInitAndRunTask() function.
69   explicit MTPDeviceDelegateImplLinux(const std::string& device_location);
70 
71   // Destructed via CancelPendingTasksAndDeleteDelegate().
72   virtual ~MTPDeviceDelegateImplLinux();
73 
74   // MTPDeviceAsyncDelegate:
75   virtual void GetFileInfo(const base::FilePath& file_path,
76                            const GetFileInfoSuccessCallback& success_callback,
77                            const ErrorCallback& error_callback) OVERRIDE;
78   virtual void ReadDirectory(
79       const base::FilePath& root,
80       const ReadDirectorySuccessCallback& success_callback,
81       const ErrorCallback& error_callback) OVERRIDE;
82   virtual void CreateSnapshotFile(
83       const base::FilePath& device_file_path,
84       const base::FilePath& local_path,
85       const CreateSnapshotFileSuccessCallback& success_callback,
86       const ErrorCallback& error_callback) OVERRIDE;
87   virtual bool IsStreaming() OVERRIDE;
88   virtual void ReadBytes(const base::FilePath& device_file_path,
89                          const scoped_refptr<net::IOBuffer>& buf,
90                          int64 offset,
91                          int buf_len,
92                          const ReadBytesSuccessCallback& success_callback,
93                          const ErrorCallback& error_callback) OVERRIDE;
94   virtual void CancelPendingTasksAndDeleteDelegate() OVERRIDE;
95 
96   // The internal methods correspond to the similarly named methods above.
97   // The |root_node_| cache should be filled at this point.
98   virtual void GetFileInfoInternal(
99       const base::FilePath& file_path,
100       const GetFileInfoSuccessCallback& success_callback,
101       const ErrorCallback& error_callback);
102   virtual void ReadDirectoryInternal(
103       const base::FilePath& root,
104       const ReadDirectorySuccessCallback& success_callback,
105       const ErrorCallback& error_callback);
106   virtual void CreateSnapshotFileInternal(
107       const base::FilePath& device_file_path,
108       const base::FilePath& local_path,
109       const CreateSnapshotFileSuccessCallback& success_callback,
110       const ErrorCallback& error_callback);
111   virtual void ReadBytesInternal(
112       const base::FilePath& device_file_path,
113       net::IOBuffer* buf, int64 offset, int buf_len,
114       const ReadBytesSuccessCallback& success_callback,
115       const ErrorCallback& error_callback);
116 
117   // Ensures the device is initialized for communication.
118   // If the device is already initialized, call RunTask().
119   //
120   // If the device is uninitialized, store the |task_info| in a pending task
121   // queue and runs the pending tasks in the queue once the device is
122   // successfully initialized.
123   void EnsureInitAndRunTask(const PendingTaskInfo& task_info);
124 
125   // Runs a task. If |task_info.path| is empty, or if the path is cached, runs
126   // the task immediately.
127   // Otherwise, fills the cache first before running the task.
128   // |task_info.task| runs on the UI thread.
129   void RunTask(const PendingTaskInfo& task_info);
130 
131   // Writes data from the device to the snapshot file path based on the
132   // parameters in |current_snapshot_request_info_| by doing a call-and-reply to
133   // the UI thread.
134   //
135   // |snapshot_file_info| specifies the metadata details of the snapshot file.
136   void WriteDataIntoSnapshotFile(const base::File::Info& snapshot_file_info);
137 
138   // Marks the current request as complete and call ProcessNextPendingRequest().
139   void PendingRequestDone();
140 
141   // Processes the next pending request.
142   void ProcessNextPendingRequest();
143 
144   // Handles the device initialization event. |succeeded| indicates whether
145   // device initialization succeeded.
146   //
147   // If the device is successfully initialized, runs the next pending task.
148   void OnInitCompleted(bool succeeded);
149 
150   // Called when GetFileInfo() succeeds. |file_info| specifies the
151   // requested file details. |success_callback| is invoked to notify the caller
152   // about the requested file details.
153   void OnDidGetFileInfo(const GetFileInfoSuccessCallback& success_callback,
154                         const base::File::Info& file_info);
155 
156   // Called when GetFileInfo() succeeds. GetFileInfo() is invoked to
157   // get the |dir_id| directory metadata details. |file_info| specifies the
158   // |dir_id| directory details.
159   //
160   // If |dir_id| is a directory, post a task on the UI thread to read the
161   // |dir_id| directory file entries.
162   //
163   // If |dir_id| is not a directory, |error_callback| is invoked to notify the
164   // caller about the file error and process the next pending request.
165   void OnDidGetFileInfoToReadDirectory(
166       uint32 dir_id,
167       const ReadDirectorySuccessCallback& success_callback,
168       const ErrorCallback& error_callback,
169       const base::File::Info& file_info);
170 
171   // Called when GetFileInfo() succeeds. GetFileInfo() is invoked to
172   // create the snapshot file of |snapshot_request_info.device_file_path|.
173   // |file_info| specifies the device file metadata details.
174   //
175   // Posts a task on the UI thread to copy the data contents of the device file
176   // to the snapshot file.
177   void OnDidGetFileInfoToCreateSnapshotFile(
178       scoped_ptr<SnapshotRequestInfo> snapshot_request_info,
179       const base::File::Info& file_info);
180 
181   // Called when ReadDirectory() succeeds.
182   //
183   // |dir_id| is the directory read.
184   // |success_callback| is invoked to notify the caller about the directory
185   // file entries.
186   // |file_list| contains the directory file entries with their file ids.
187   // |has_more| is true if there are more file entries to read.
188   void OnDidReadDirectory(uint32 dir_id,
189                           const ReadDirectorySuccessCallback& success_callback,
190                           const storage::AsyncFileUtil::EntryList& file_list,
191                           bool has_more);
192 
193   // Called when WriteDataIntoSnapshotFile() succeeds.
194   //
195   // |snapshot_file_info| specifies the snapshot file metadata details.
196   //
197   // |current_snapshot_request_info_.success_callback| is invoked to notify the
198   // caller about |snapshot_file_info|.
199   void OnDidWriteDataIntoSnapshotFile(
200       const base::File::Info& snapshot_file_info,
201       const base::FilePath& snapshot_file_path);
202 
203   // Called when WriteDataIntoSnapshotFile() fails.
204   //
205   // |error| specifies the file error code.
206   //
207   // |current_snapshot_request_info_.error_callback| is invoked to notify the
208   // caller about |error|.
209   void OnWriteDataIntoSnapshotFileError(base::File::Error error);
210 
211   // Called when ReadBytes() succeeds.
212   //
213   // |success_callback| is invoked to notify the caller about the read bytes.
214   // |bytes_read| is the number of bytes read.
215   void OnDidReadBytes(const ReadBytesSuccessCallback& success_callback,
216                       const base::File::Info& file_info, int bytes_read);
217 
218   // Called when FillFileCache() succeeds.
219   void OnDidFillFileCache(const base::FilePath& path,
220                           const storage::AsyncFileUtil::EntryList& file_list,
221                           bool has_more);
222 
223   // Called when FillFileCache() fails.
224   void OnFillFileCacheFailed(base::File::Error error);
225 
226   // Handles the device file |error| while operating on |file_id|.
227   // |error_callback| is invoked to notify the caller about the file error.
228   void HandleDeviceFileError(const ErrorCallback& error_callback,
229                              uint32 file_id,
230                              base::File::Error error);
231 
232   // Given a full path, returns a non-empty sub-path that needs to be read into
233   // the cache if such a uncached path exists.
234   // |cached_path| is the portion of |path| that has had cache lookup attempts.
235   base::FilePath NextUncachedPathComponent(
236       const base::FilePath& path,
237       const base::FilePath& cached_path) const;
238 
239   // Fills the file cache using the results from NextUncachedPathComponent().
240   void FillFileCache(const base::FilePath& uncached_path);
241 
242   // Given a full path, if it exists in the cache, writes the file's id to |id|
243   // and return true.
244   bool CachedPathToId(const base::FilePath& path, uint32* id) const;
245 
246   // MTP device initialization state.
247   InitializationState init_state_;
248 
249   // Used to make sure only one task is in progress at any time.
250   // Otherwise the browser will try to send too many requests at once and
251   // overload the device.
252   bool task_in_progress_;
253 
254   // Registered file system device path. This path does not
255   // correspond to a real device path (e.g. "/usb:2,2:81282").
256   const base::FilePath device_path_;
257 
258   // MTP device storage name (e.g. "usb:2,2:81282").
259   std::string storage_name_;
260 
261   // A list of pending tasks that needs to be run when the device is
262   // initialized or when the current task in progress is complete.
263   std::deque<PendingTaskInfo> pending_tasks_;
264 
265   // Used to track the current snapshot file request. A snapshot file is created
266   // incrementally. CreateSnapshotFile request reads the device file and writes
267   // to the snapshot file in chunks. In order to retain the order of the
268   // snapshot file requests, make sure there is only one active snapshot file
269   // request at any time.
270   scoped_ptr<SnapshotRequestInfo> current_snapshot_request_info_;
271 
272   // A mapping for quick lookups into the |root_node_| tree structure. Since
273   // |root_node_| contains pointers to this map, it must be declared after this
274   // so destruction happens in the right order.
275   FileIdToMTPFileNodeMap file_id_to_node_map_;
276 
277   // The root node of a tree-structure that caches the directory structure of
278   // the MTP device.
279   scoped_ptr<MTPFileNode> root_node_;
280 
281   // A list of child nodes encountered while a ReadDirectory operation, which
282   // can return results over multiple callbacks, is in progress.
283   std::set<std::string> child_nodes_seen_;
284 
285   // A cache to store file metadata for file entries read during a ReadDirectory
286   // operation. Used to service incoming GetFileInfo calls for the duration of
287   // the ReadDirectory operation.
288   FileInfoCache file_info_cache_;
289 
290   // For callbacks that may run after destruction.
291   base::WeakPtrFactory<MTPDeviceDelegateImplLinux> weak_ptr_factory_;
292 
293   DISALLOW_COPY_AND_ASSIGN(MTPDeviceDelegateImplLinux);
294 };
295 
296 #endif  // CHROME_BROWSER_MEDIA_GALLERIES_LINUX_MTP_DEVICE_DELEGATE_IMPL_LINUX_H_
297