1 // Copyright (c) 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 CHROME_BROWSER_MEDIA_GALLERIES_WIN_MTP_DEVICE_DELEGATE_IMPL_WIN_H_ 6 #define CHROME_BROWSER_MEDIA_GALLERIES_WIN_MTP_DEVICE_DELEGATE_IMPL_WIN_H_ 7 8 #include <queue> 9 10 #include "base/callback.h" 11 #include "base/files/file.h" 12 #include "base/location.h" 13 #include "base/memory/scoped_ptr.h" 14 #include "base/memory/weak_ptr.h" 15 #include "base/strings/string16.h" 16 #include "base/win/scoped_comptr.h" 17 #include "chrome/browser/media_galleries/fileapi/mtp_device_async_delegate.h" 18 #include "webkit/browser/fileapi/async_file_util.h" 19 20 namespace base { 21 class FilePath; 22 class SequencedTaskRunner; 23 } 24 25 class SnapshotFileDetails; 26 struct SnapshotRequestInfo; 27 28 // MTPDeviceDelegateImplWin is used to communicate with the media transfer 29 // protocol (MTP) device to complete file system operations. These operations 30 // are performed asynchronously on a blocking pool thread since the device 31 // access may be slow and may take a long time to complete. MTP 32 // device can have multiple data storage partitions. MTPDeviceDelegateImplWin 33 // is instantiated per MTP device storage partition using 34 // CreateMTPDeviceAsyncDelegate(). MTPDeviceDelegateImplWin lives on the IO 35 // thread. 36 class MTPDeviceDelegateImplWin : public MTPDeviceAsyncDelegate { 37 public: 38 // Structure used to represent MTP device storage partition details. 39 struct StorageDeviceInfo { 40 StorageDeviceInfo(const base::string16& pnp_device_id, 41 const base::string16& registered_device_path, 42 const base::string16& storage_object_id); 43 44 // The PnP Device Id, used to open the device for communication, 45 // e.g. "\\?\usb#vid_04a9&pid_3073#12#{6ac27878-a6fa-4155-ba85-f1d4f33}". 46 const base::string16 pnp_device_id; 47 48 // The media file system root path, which is obtained during the 49 // registration of MTP device storage partition as a file system, 50 // e.g. "\\MTP:StorageSerial:SID-{10001,E,9823}:237483". 51 const base::string16 registered_device_path; 52 53 // The MTP device storage partition object identifier, used to enumerate the 54 // storage contents, e.g. "s10001". 55 const base::string16 storage_object_id; 56 }; 57 58 private: 59 friend void OnGetStorageInfoCreateDelegate( 60 const base::string16& device_location, 61 const CreateMTPDeviceAsyncDelegateCallback& callback, 62 base::string16* pnp_device_id, 63 base::string16* storage_object_id, 64 bool succeeded); 65 66 enum InitializationState { 67 UNINITIALIZED = 0, 68 PENDING_INIT, 69 INITIALIZED 70 }; 71 72 // Used to represent pending task details. 73 struct PendingTaskInfo { 74 PendingTaskInfo(const tracked_objects::Location& location, 75 const base::Callback<base::File::Error(void)>& task, 76 const base::Callback<void(base::File::Error)>& reply); 77 78 const tracked_objects::Location location; 79 const base::Callback<base::File::Error(void)> task; 80 const base::Callback<void(base::File::Error)> reply; 81 }; 82 83 // Defers the device initializations until the first file operation request. 84 // Do all the initializations in EnsureInitAndRunTask() function. 85 MTPDeviceDelegateImplWin(const base::string16& registered_device_path, 86 const base::string16& pnp_device_id, 87 const base::string16& storage_object_id); 88 89 // Destructed via CancelPendingTasksAndDeleteDelegate(). 90 virtual ~MTPDeviceDelegateImplWin(); 91 92 // MTPDeviceAsyncDelegate: 93 virtual void GetFileInfo( 94 const base::FilePath& file_path, 95 const GetFileInfoSuccessCallback& success_callback, 96 const ErrorCallback& error_callback) OVERRIDE; 97 virtual void ReadDirectory( 98 const base::FilePath& root, 99 const ReadDirectorySuccessCallback& success_callback, 100 const ErrorCallback& error_callback) OVERRIDE; 101 virtual void CreateSnapshotFile( 102 const base::FilePath& device_file_path, 103 const base::FilePath& local_path, 104 const CreateSnapshotFileSuccessCallback& success_callback, 105 const ErrorCallback& error_callback) OVERRIDE; 106 virtual bool IsStreaming() OVERRIDE; 107 virtual void ReadBytes( 108 const base::FilePath& device_file_path, 109 net::IOBuffer* buf, int64 offset, int buf_len, 110 const ReadBytesSuccessCallback& success_callback, 111 const ErrorCallback& error_callback) OVERRIDE; 112 virtual void CancelPendingTasksAndDeleteDelegate() OVERRIDE; 113 114 // Ensures the device is initialized for communication by doing a 115 // call-and-reply to a blocking pool thread. |task_info.task| runs on a 116 // blocking pool thread and |task_info.reply| runs on the IO thread. 117 // 118 // If the device is already initialized, post the |task_info.task| 119 // immediately on a blocking pool thread. 120 // 121 // If the device is uninitialized, store the |task_info| in a pending task 122 // list and then runs all the pending tasks once the device is successfully 123 // initialized. 124 void EnsureInitAndRunTask(const PendingTaskInfo& task_info); 125 126 // Writes data chunk from the device to the snapshot file path based on the 127 // parameters in |current_snapshot_details_| by doing a call-and-reply to a 128 // blocking pool thread. 129 void WriteDataChunkIntoSnapshotFile(); 130 131 // Processes the next pending request. 132 void ProcessNextPendingRequest(); 133 134 // Handles the event that the device is initialized. |succeeded| indicates 135 // whether device initialization succeeded or not. If the device is 136 // successfully initialized, runs the next pending task. 137 void OnInitCompleted(bool succeeded); 138 139 // Called when GetFileInfo() completes. |file_info| specifies the requested 140 // file details. |error| specifies the platform file error code. 141 // 142 // If the GetFileInfo() succeeds, |success_callback| is invoked to notify the 143 // caller about the |file_info| details. 144 // 145 // If the GetFileInfo() fails, |file_info| is not set and |error_callback| is 146 // invoked to notify the caller about the platform file |error|. 147 void OnGetFileInfo(const GetFileInfoSuccessCallback& success_callback, 148 const ErrorCallback& error_callback, 149 base::File::Info* file_info, 150 base::File::Error error); 151 152 // Called when ReadDirectory() completes. |file_list| contains the directory 153 // file entries information. |error| specifies the platform file error code. 154 // 155 // If the ReadDirectory() succeeds, |success_callback| is invoked to notify 156 // the caller about the directory file entries. 157 // 158 // If the ReadDirectory() fails, |file_list| is not set and |error_callback| 159 // is invoked to notify the caller about the platform file |error|. 160 void OnDidReadDirectory(const ReadDirectorySuccessCallback& success_callback, 161 const ErrorCallback& error_callback, 162 fileapi::AsyncFileUtil::EntryList* file_list, 163 base::File::Error error); 164 165 // Called when the get file stream request completes. 166 // |file_details.request_info| contains the CreateSnapshot request param 167 // details. |error| specifies the platform file error code. 168 // 169 // If the file stream of the device file is successfully 170 // fetched, |file_details| will contain the required details for the creation 171 // of the snapshot file. 172 // 173 // If the get file stream request fails, |error| is set accordingly. 174 void OnGetFileStream(scoped_ptr<SnapshotFileDetails> file_details, 175 base::File::Error error); 176 177 // Called when WriteDataChunkIntoSnapshotFile() completes. 178 // |bytes_written| specifies the number of bytes written into the 179 // |snapshot_file_path| during the last write operation. 180 // 181 // If the write operation succeeds, |bytes_written| is set to a non-zero 182 // value. 183 // 184 // If the write operation fails, |bytes_written| is set to zero. 185 void OnWroteDataChunkIntoSnapshotFile( 186 const base::FilePath& snapshot_file_path, 187 DWORD bytes_written); 188 189 // Portable device initialization state. 190 InitializationState init_state_; 191 192 // The task runner where the device operation tasks runs. 193 scoped_refptr<base::SequencedTaskRunner> media_task_runner_; 194 195 // Device storage partition details 196 // (e.g. device path, PnP device id and storage object id). 197 StorageDeviceInfo storage_device_info_; 198 199 // Used to track the current state of the snapshot file (e.g how many bytes 200 // written to the snapshot file, optimal data transfer size, source file 201 // stream, etc). 202 // 203 // A snapshot file is created incrementally. CreateSnapshotFile request reads 204 // and writes the snapshot file data in chunks. In order to retain the order 205 // of the snapshot file requests, make sure there is only one active snapshot 206 // file request at any time. 207 scoped_ptr<SnapshotFileDetails> current_snapshot_details_; 208 209 // A list of pending tasks that needs to be run when the device is 210 // initialized or when the current task in progress is complete. 211 std::queue<PendingTaskInfo> pending_tasks_; 212 213 // Used to make sure only one task is in progress at any time. 214 bool task_in_progress_; 215 216 // For callbacks that may run after destruction. 217 base::WeakPtrFactory<MTPDeviceDelegateImplWin> weak_ptr_factory_; 218 219 DISALLOW_COPY_AND_ASSIGN(MTPDeviceDelegateImplWin); 220 }; 221 222 #endif // CHROME_BROWSER_MEDIA_GALLERIES_WIN_MTP_DEVICE_DELEGATE_IMPL_WIN_H_ 223