OLD | NEW |
| (Empty) |
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 #include "chrome/browser/media_transfer_protocol/media_transfer_protocol_manager
.h" | |
6 | |
7 #include <map> | |
8 #include <queue> | |
9 #include <set> | |
10 #include <utility> | |
11 | |
12 #include "base/bind.h" | |
13 #include "base/command_line.h" | |
14 #include "base/memory/weak_ptr.h" | |
15 #include "base/observer_list.h" | |
16 #include "base/stl_util.h" | |
17 #include "chrome/browser/media_transfer_protocol/media_transfer_protocol_daemon_
client.h" | |
18 #include "chrome/browser/media_transfer_protocol/mtp_file_entry.pb.h" | |
19 #include "chrome/browser/media_transfer_protocol/mtp_storage_info.pb.h" | |
20 #include "chrome/common/chrome_switches.h" | |
21 #include "content/public/browser/browser_thread.h" | |
22 | |
23 #if defined(OS_CHROMEOS) | |
24 #include "chromeos/dbus/dbus_thread_manager.h" | |
25 #else | |
26 #include "dbus/bus.h" | |
27 #endif | |
28 | |
29 using content::BrowserThread; | |
30 | |
31 namespace chrome { | |
32 | |
33 namespace { | |
34 | |
35 MediaTransferProtocolManager* g_media_transfer_protocol_manager = NULL; | |
36 | |
37 // The MediaTransferProtocolManager implementation. | |
38 class MediaTransferProtocolManagerImpl : public MediaTransferProtocolManager { | |
39 public: | |
40 MediaTransferProtocolManagerImpl() : weak_ptr_factory_(this) { | |
41 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kTestType)) | |
42 return; | |
43 | |
44 dbus::Bus* bus = NULL; | |
45 #if defined(OS_CHROMEOS) | |
46 chromeos::DBusThreadManager* dbus_thread_manager = | |
47 chromeos::DBusThreadManager::Get(); | |
48 bus = dbus_thread_manager->GetSystemBus(); | |
49 if (!bus) | |
50 return; | |
51 #else | |
52 dbus::Bus::Options options; | |
53 options.bus_type = dbus::Bus::SYSTEM; | |
54 options.connection_type = dbus::Bus::PRIVATE; | |
55 options.dbus_thread_message_loop_proxy = | |
56 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE); | |
57 session_bus_ = new dbus::Bus(options); | |
58 bus = session_bus_.get(); | |
59 #endif | |
60 | |
61 DCHECK(bus); | |
62 mtp_client_.reset( | |
63 MediaTransferProtocolDaemonClient::Create(bus, false /* not stub */)); | |
64 | |
65 // Set up signals and start initializing |storage_info_map_|. | |
66 mtp_client_->SetUpConnections( | |
67 base::Bind(&MediaTransferProtocolManagerImpl::OnStorageChanged, | |
68 weak_ptr_factory_.GetWeakPtr())); | |
69 mtp_client_->EnumerateStorages( | |
70 base::Bind(&MediaTransferProtocolManagerImpl::OnEnumerateStorages, | |
71 weak_ptr_factory_.GetWeakPtr()), | |
72 base::Bind(&base::DoNothing)); | |
73 } | |
74 | |
75 virtual ~MediaTransferProtocolManagerImpl() { | |
76 } | |
77 | |
78 // MediaTransferProtocolManager override. | |
79 virtual void AddObserver(Observer* observer) OVERRIDE { | |
80 observers_.AddObserver(observer); | |
81 } | |
82 | |
83 // MediaTransferProtocolManager override. | |
84 virtual void RemoveObserver(Observer* observer) OVERRIDE { | |
85 observers_.RemoveObserver(observer); | |
86 } | |
87 | |
88 // MediaTransferProtocolManager override. | |
89 const std::vector<std::string> GetStorages() const OVERRIDE { | |
90 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
91 std::vector<std::string> storages; | |
92 for (StorageInfoMap::const_iterator it = storage_info_map_.begin(); | |
93 it != storage_info_map_.end(); | |
94 ++it) { | |
95 storages.push_back(it->first); | |
96 } | |
97 return storages; | |
98 } | |
99 | |
100 // MediaTransferProtocolManager override. | |
101 virtual const MtpStorageInfo* GetStorageInfo( | |
102 const std::string& storage_name) const OVERRIDE { | |
103 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
104 StorageInfoMap::const_iterator it = storage_info_map_.find(storage_name); | |
105 if (it == storage_info_map_.end()) | |
106 return NULL; | |
107 return &it->second; | |
108 } | |
109 | |
110 // MediaTransferProtocolManager override. | |
111 virtual void OpenStorage(const std::string& storage_name, | |
112 const std::string& mode, | |
113 const OpenStorageCallback& callback) OVERRIDE { | |
114 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
115 if (!ContainsKey(storage_info_map_, storage_name)) { | |
116 callback.Run("", true); | |
117 return; | |
118 } | |
119 open_storage_callbacks_.push(callback); | |
120 mtp_client_->OpenStorage( | |
121 storage_name, | |
122 mode, | |
123 base::Bind(&MediaTransferProtocolManagerImpl::OnOpenStorage, | |
124 weak_ptr_factory_.GetWeakPtr()), | |
125 base::Bind(&MediaTransferProtocolManagerImpl::OnOpenStorageError, | |
126 weak_ptr_factory_.GetWeakPtr())); | |
127 } | |
128 | |
129 // MediaTransferProtocolManager override. | |
130 virtual void CloseStorage(const std::string& storage_handle, | |
131 const CloseStorageCallback& callback) OVERRIDE { | |
132 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
133 if (!ContainsKey(handles_, storage_handle)) { | |
134 callback.Run(true); | |
135 return; | |
136 } | |
137 close_storage_callbacks_.push(std::make_pair(callback, storage_handle)); | |
138 mtp_client_->CloseStorage( | |
139 storage_handle, | |
140 base::Bind(&MediaTransferProtocolManagerImpl::OnCloseStorage, | |
141 weak_ptr_factory_.GetWeakPtr()), | |
142 base::Bind(&MediaTransferProtocolManagerImpl::OnCloseStorageError, | |
143 weak_ptr_factory_.GetWeakPtr())); | |
144 } | |
145 | |
146 // MediaTransferProtocolManager override. | |
147 virtual void ReadDirectoryByPath( | |
148 const std::string& storage_handle, | |
149 const std::string& path, | |
150 const ReadDirectoryCallback& callback) OVERRIDE { | |
151 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
152 if (!ContainsKey(handles_, storage_handle)) { | |
153 callback.Run(std::vector<MtpFileEntry>(), true); | |
154 return; | |
155 } | |
156 read_directory_callbacks_.push(callback); | |
157 mtp_client_->ReadDirectoryByPath( | |
158 storage_handle, | |
159 path, | |
160 base::Bind(&MediaTransferProtocolManagerImpl::OnReadDirectory, | |
161 weak_ptr_factory_.GetWeakPtr()), | |
162 base::Bind(&MediaTransferProtocolManagerImpl::OnReadDirectoryError, | |
163 weak_ptr_factory_.GetWeakPtr())); | |
164 } | |
165 | |
166 // MediaTransferProtocolManager override. | |
167 virtual void ReadDirectoryById( | |
168 const std::string& storage_handle, | |
169 uint32 file_id, | |
170 const ReadDirectoryCallback& callback) OVERRIDE { | |
171 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
172 if (!ContainsKey(handles_, storage_handle)) { | |
173 callback.Run(std::vector<MtpFileEntry>(), true); | |
174 return; | |
175 } | |
176 read_directory_callbacks_.push(callback); | |
177 mtp_client_->ReadDirectoryById( | |
178 storage_handle, | |
179 file_id, | |
180 base::Bind(&MediaTransferProtocolManagerImpl::OnReadDirectory, | |
181 weak_ptr_factory_.GetWeakPtr()), | |
182 base::Bind(&MediaTransferProtocolManagerImpl::OnReadDirectoryError, | |
183 weak_ptr_factory_.GetWeakPtr())); | |
184 } | |
185 | |
186 // MediaTransferProtocolManager override. | |
187 virtual void ReadFileChunkByPath(const std::string& storage_handle, | |
188 const std::string& path, | |
189 uint32 offset, | |
190 uint32 count, | |
191 const ReadFileCallback& callback) OVERRIDE { | |
192 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
193 if (!ContainsKey(handles_, storage_handle)) { | |
194 callback.Run(std::string(), true); | |
195 return; | |
196 } | |
197 read_file_callbacks_.push(callback); | |
198 mtp_client_->ReadFileChunkByPath( | |
199 storage_handle, path, offset, count, | |
200 base::Bind(&MediaTransferProtocolManagerImpl::OnReadFile, | |
201 weak_ptr_factory_.GetWeakPtr()), | |
202 base::Bind(&MediaTransferProtocolManagerImpl::OnReadFileError, | |
203 weak_ptr_factory_.GetWeakPtr())); | |
204 } | |
205 | |
206 // MediaTransferProtocolManager override. | |
207 virtual void ReadFileChunkById(const std::string& storage_handle, | |
208 uint32 file_id, | |
209 uint32 offset, | |
210 uint32 count, | |
211 const ReadFileCallback& callback) OVERRIDE { | |
212 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
213 if (!ContainsKey(handles_, storage_handle)) { | |
214 callback.Run(std::string(), true); | |
215 return; | |
216 } | |
217 read_file_callbacks_.push(callback); | |
218 mtp_client_->ReadFileChunkById( | |
219 storage_handle, file_id, offset, count, | |
220 base::Bind(&MediaTransferProtocolManagerImpl::OnReadFile, | |
221 weak_ptr_factory_.GetWeakPtr()), | |
222 base::Bind(&MediaTransferProtocolManagerImpl::OnReadFileError, | |
223 weak_ptr_factory_.GetWeakPtr())); | |
224 } | |
225 | |
226 virtual void GetFileInfoByPath(const std::string& storage_handle, | |
227 const std::string& path, | |
228 const GetFileInfoCallback& callback) OVERRIDE { | |
229 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
230 if (!ContainsKey(handles_, storage_handle)) { | |
231 callback.Run(MtpFileEntry(), true); | |
232 return; | |
233 } | |
234 get_file_info_callbacks_.push(callback); | |
235 mtp_client_->GetFileInfoByPath( | |
236 storage_handle, | |
237 path, | |
238 base::Bind(&MediaTransferProtocolManagerImpl::OnGetFileInfo, | |
239 weak_ptr_factory_.GetWeakPtr()), | |
240 base::Bind(&MediaTransferProtocolManagerImpl::OnGetFileInfoError, | |
241 weak_ptr_factory_.GetWeakPtr())); | |
242 } | |
243 | |
244 virtual void GetFileInfoById(const std::string& storage_handle, | |
245 uint32 file_id, | |
246 const GetFileInfoCallback& callback) OVERRIDE { | |
247 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
248 if (!ContainsKey(handles_, storage_handle)) { | |
249 callback.Run(MtpFileEntry(), true); | |
250 return; | |
251 } | |
252 get_file_info_callbacks_.push(callback); | |
253 mtp_client_->GetFileInfoById( | |
254 storage_handle, | |
255 file_id, | |
256 base::Bind(&MediaTransferProtocolManagerImpl::OnGetFileInfo, | |
257 weak_ptr_factory_.GetWeakPtr()), | |
258 base::Bind(&MediaTransferProtocolManagerImpl::OnGetFileInfoError, | |
259 weak_ptr_factory_.GetWeakPtr())); | |
260 } | |
261 | |
262 private: | |
263 // Map of storage names to storage info. | |
264 typedef std::map<std::string, MtpStorageInfo> StorageInfoMap; | |
265 // Callback queues - DBus communication is in-order, thus callbacks are | |
266 // received in the same order as the requests. | |
267 typedef std::queue<OpenStorageCallback> OpenStorageCallbackQueue; | |
268 // (callback, handle) | |
269 typedef std::queue<std::pair<CloseStorageCallback, std::string> | |
270 > CloseStorageCallbackQueue; | |
271 typedef std::queue<ReadDirectoryCallback> ReadDirectoryCallbackQueue; | |
272 typedef std::queue<ReadFileCallback> ReadFileCallbackQueue; | |
273 typedef std::queue<GetFileInfoCallback> GetFileInfoCallbackQueue; | |
274 | |
275 void OnStorageChanged(bool is_attach, const std::string& storage_name) { | |
276 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
277 if (is_attach) { | |
278 mtp_client_->GetStorageInfo( | |
279 storage_name, | |
280 base::Bind(&MediaTransferProtocolManagerImpl::OnGetStorageInfo, | |
281 weak_ptr_factory_.GetWeakPtr()), | |
282 base::Bind(&base::DoNothing)); | |
283 return; | |
284 } | |
285 | |
286 // Detach case. | |
287 StorageInfoMap::iterator it = storage_info_map_.find(storage_name); | |
288 if (it == storage_info_map_.end()) { | |
289 // This might happen during initialization when |storage_info_map_| has | |
290 // not been fully populated yet? | |
291 return; | |
292 } | |
293 storage_info_map_.erase(it); | |
294 FOR_EACH_OBSERVER(Observer, | |
295 observers_, | |
296 StorageChanged(false /* detach */, storage_name)); | |
297 } | |
298 | |
299 void OnEnumerateStorages(const std::vector<std::string>& storage_names) { | |
300 for (size_t i = 0; i < storage_names.size(); ++i) { | |
301 mtp_client_->GetStorageInfo( | |
302 storage_names[i], | |
303 base::Bind(&MediaTransferProtocolManagerImpl::OnGetStorageInfo, | |
304 weak_ptr_factory_.GetWeakPtr()), | |
305 base::Bind(&base::DoNothing)); | |
306 } | |
307 } | |
308 | |
309 void OnGetStorageInfo(const MtpStorageInfo& storage_info) { | |
310 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
311 const std::string& storage_name = storage_info.storage_name(); | |
312 if (ContainsKey(storage_info_map_, storage_name)) { | |
313 // This should not happen, since MediaTransferProtocolManagerImpl should | |
314 // only call EnumerateStorages() once, which populates |storage_info_map_| | |
315 // with the already-attached devices. | |
316 // After that, all incoming signals are either for new storage | |
317 // attachments, which should not be in |storage_info_map_|, or for | |
318 // storage detachements, which do not add to |storage_info_map_|. | |
319 NOTREACHED(); | |
320 return; | |
321 } | |
322 | |
323 // New storage. Add it and let the observers know. | |
324 storage_info_map_.insert(std::make_pair(storage_name, storage_info)); | |
325 FOR_EACH_OBSERVER(Observer, | |
326 observers_, | |
327 StorageChanged(true /* is attach */, storage_name)); | |
328 } | |
329 | |
330 void OnOpenStorage(const std::string& handle) { | |
331 if (!ContainsKey(handles_, handle)) { | |
332 handles_.insert(handle); | |
333 open_storage_callbacks_.front().Run(handle, false); | |
334 } else { | |
335 NOTREACHED(); | |
336 open_storage_callbacks_.front().Run("", true); | |
337 } | |
338 open_storage_callbacks_.pop(); | |
339 } | |
340 | |
341 void OnOpenStorageError() { | |
342 open_storage_callbacks_.front().Run("", true); | |
343 open_storage_callbacks_.pop(); | |
344 } | |
345 | |
346 void OnCloseStorage() { | |
347 const std::string& handle = close_storage_callbacks_.front().second; | |
348 if (ContainsKey(handles_, handle)) { | |
349 handles_.erase(handle); | |
350 close_storage_callbacks_.front().first.Run(false); | |
351 } else { | |
352 NOTREACHED(); | |
353 close_storage_callbacks_.front().first.Run(true); | |
354 } | |
355 close_storage_callbacks_.pop(); | |
356 } | |
357 | |
358 void OnCloseStorageError() { | |
359 close_storage_callbacks_.front().first.Run(true); | |
360 close_storage_callbacks_.pop(); | |
361 } | |
362 | |
363 void OnReadDirectory(const std::vector<MtpFileEntry>& file_entries) { | |
364 read_directory_callbacks_.front().Run(file_entries, false); | |
365 read_directory_callbacks_.pop(); | |
366 } | |
367 | |
368 void OnReadDirectoryError() { | |
369 read_directory_callbacks_.front().Run(std::vector<MtpFileEntry>(), true); | |
370 read_directory_callbacks_.pop(); | |
371 } | |
372 | |
373 void OnReadFile(const std::string& data) { | |
374 read_file_callbacks_.front().Run(data, false); | |
375 read_file_callbacks_.pop(); | |
376 } | |
377 | |
378 void OnReadFileError() { | |
379 read_file_callbacks_.front().Run(std::string(), true); | |
380 read_file_callbacks_.pop(); | |
381 } | |
382 | |
383 void OnGetFileInfo(const MtpFileEntry& entry) { | |
384 get_file_info_callbacks_.front().Run(entry, false); | |
385 get_file_info_callbacks_.pop(); | |
386 } | |
387 | |
388 void OnGetFileInfoError() { | |
389 get_file_info_callbacks_.front().Run(MtpFileEntry(), true); | |
390 get_file_info_callbacks_.pop(); | |
391 } | |
392 | |
393 // Mtpd DBus client. | |
394 scoped_ptr<chrome::MediaTransferProtocolDaemonClient> mtp_client_; | |
395 | |
396 #if !defined(OS_CHROMEOS) | |
397 // And a D-Bus session for talking to mtpd. | |
398 scoped_refptr<dbus::Bus> session_bus_; | |
399 #endif | |
400 | |
401 // Device attachment / detachment observers. | |
402 ObserverList<Observer> observers_; | |
403 | |
404 base::WeakPtrFactory<MediaTransferProtocolManagerImpl> weak_ptr_factory_; | |
405 | |
406 // Everything below is only accessed on the UI thread. | |
407 | |
408 // Map to keep track of attached storages by name. | |
409 StorageInfoMap storage_info_map_; | |
410 | |
411 // Set of open storage handles. | |
412 std::set<std::string> handles_; | |
413 | |
414 // Queued callbacks. | |
415 OpenStorageCallbackQueue open_storage_callbacks_; | |
416 CloseStorageCallbackQueue close_storage_callbacks_; | |
417 ReadDirectoryCallbackQueue read_directory_callbacks_; | |
418 ReadFileCallbackQueue read_file_callbacks_; | |
419 GetFileInfoCallbackQueue get_file_info_callbacks_; | |
420 | |
421 DISALLOW_COPY_AND_ASSIGN(MediaTransferProtocolManagerImpl); | |
422 }; | |
423 | |
424 } // namespace | |
425 | |
426 // static | |
427 void MediaTransferProtocolManager::Initialize() { | |
428 if (g_media_transfer_protocol_manager) { | |
429 LOG(WARNING) << "MediaTransferProtocolManager was already initialized"; | |
430 return; | |
431 } | |
432 g_media_transfer_protocol_manager = new MediaTransferProtocolManagerImpl(); | |
433 VLOG(1) << "MediaTransferProtocolManager initialized"; | |
434 } | |
435 | |
436 // static | |
437 void MediaTransferProtocolManager::Shutdown() { | |
438 if (!g_media_transfer_protocol_manager) { | |
439 LOG(WARNING) << "MediaTransferProtocolManager::Shutdown() called with " | |
440 << "NULL manager"; | |
441 return; | |
442 } | |
443 delete g_media_transfer_protocol_manager; | |
444 g_media_transfer_protocol_manager = NULL; | |
445 VLOG(1) << "MediaTransferProtocolManager Shutdown completed"; | |
446 } | |
447 | |
448 // static | |
449 MediaTransferProtocolManager* MediaTransferProtocolManager::GetInstance() { | |
450 return g_media_transfer_protocol_manager; | |
451 } | |
452 | |
453 } // namespace chrome | |
OLD | NEW |