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/location.h" 12 #include "base/memory/scoped_ptr.h" 13 #include "base/memory/weak_ptr.h" 14 #include "base/platform_file.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::PlatformFileError(void)>& task, 76 const base::Callback<void(base::PlatformFileError)>& reply); 77 78 const tracked_objects::Location location; 79 const base::Callback<base::PlatformFileError(void)> task; 80 const base::Callback<void(base::PlatformFileError)> 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 void CancelPendingTasksAndDeleteDelegate() OVERRIDE; 107 108 // Ensures the device is initialized for communication by doing a 109 // call-and-reply to a blocking pool thread. |task_info.task| runs on a 110 // blocking pool thread and |task_info.reply| runs on the IO thread. 111 // 112 // If the device is already initialized, post the |task_info.task| 113 // immediately on a blocking pool thread. 114 // 115 // If the device is uninitialized, store the |task_info| in a pending task 116 // list and then runs all the pending tasks once the device is successfully 117 // initialized. 118 void EnsureInitAndRunTask(const PendingTaskInfo& task_info); 119 120 // Writes data chunk from the device to the snapshot file path based on the 121 // parameters in |current_snapshot_details_| by doing a call-and-reply to a 122 // blocking pool thread. 123 void WriteDataChunkIntoSnapshotFile(); 124 125 // Processes the next pending request. 126 void ProcessNextPendingRequest(); 127 128 // Handles the event that the device is initialized. |succeeded| indicates 129 // whether device initialization succeeded or not. If the device is 130 // successfully initialized, runs the next pending task. 131 void OnInitCompleted(bool succeeded); 132 133 // Called when GetFileInfo() completes. |file_info| specifies the requested 134 // file details. |error| specifies the platform file error code. 135 // 136 // If the GetFileInfo() succeeds, |success_callback| is invoked to notify the 137 // caller about the |file_info| details. 138 // 139 // If the GetFileInfo() fails, |file_info| is not set and |error_callback| is 140 // invoked to notify the caller about the platform file |error|. 141 void OnGetFileInfo(const GetFileInfoSuccessCallback& success_callback, 142 const ErrorCallback& error_callback, 143 base::PlatformFileInfo* file_info, 144 base::PlatformFileError error); 145 146 // Called when ReadDirectory() completes. |file_list| contains the directory 147 // file entries information. |error| specifies the platform file error code. 148 // 149 // If the ReadDirectory() succeeds, |success_callback| is invoked to notify 150 // the caller about the directory file entries. 151 // 152 // If the ReadDirectory() fails, |file_list| is not set and |error_callback| 153 // is invoked to notify the caller about the platform file |error|. 154 void OnDidReadDirectory(const ReadDirectorySuccessCallback& success_callback, 155 const ErrorCallback& error_callback, 156 fileapi::AsyncFileUtil::EntryList* file_list, 157 base::PlatformFileError error); 158 159 // Called when the get file stream request completes. 160 // |file_details.request_info| contains the CreateSnapshot request param 161 // details. |error| specifies the platform file error code. 162 // 163 // If the file stream of the device file is successfully 164 // fetched, |file_details| will contain the required details for the creation 165 // of the snapshot file. 166 // 167 // If the get file stream request fails, |error| is set accordingly. 168 void OnGetFileStream(scoped_ptr<SnapshotFileDetails> file_details, 169 base::PlatformFileError error); 170 171 // Called when WriteDataChunkIntoSnapshotFile() completes. 172 // |bytes_written| specifies the number of bytes written into the 173 // |snapshot_file_path| during the last write operation. 174 // 175 // If the write operation succeeds, |bytes_written| is set to a non-zero 176 // value. 177 // 178 // If the write operation fails, |bytes_written| is set to zero. 179 void OnWroteDataChunkIntoSnapshotFile( 180 const base::FilePath& snapshot_file_path, 181 DWORD bytes_written); 182 183 // Portable device initialization state. 184 InitializationState init_state_; 185 186 // The task runner where the device operation tasks runs. 187 scoped_refptr<base::SequencedTaskRunner> media_task_runner_; 188 189 // Device storage partition details 190 // (e.g. device path, PnP device id and storage object id). 191 StorageDeviceInfo storage_device_info_; 192 193 // Used to track the current state of the snapshot file (e.g how many bytes 194 // written to the snapshot file, optimal data transfer size, source file 195 // stream, etc). 196 // 197 // A snapshot file is created incrementally. CreateSnapshotFile request reads 198 // and writes the snapshot file data in chunks. In order to retain the order 199 // of the snapshot file requests, make sure there is only one active snapshot 200 // file request at any time. 201 scoped_ptr<SnapshotFileDetails> current_snapshot_details_; 202 203 // A list of pending tasks that needs to be run when the device is 204 // initialized or when the current task in progress is complete. 205 std::queue<PendingTaskInfo> pending_tasks_; 206 207 // Used to make sure only one task is in progress at any time. 208 bool task_in_progress_; 209 210 // For callbacks that may run after destruction. 211 base::WeakPtrFactory<MTPDeviceDelegateImplWin> weak_ptr_factory_; 212 213 DISALLOW_COPY_AND_ASSIGN(MTPDeviceDelegateImplWin); 214 }; 215 216 #endif // CHROME_BROWSER_MEDIA_GALLERIES_WIN_MTP_DEVICE_DELEGATE_IMPL_WIN_H_ 217