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