1 // Copyright 2018 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 "services/device/media_transfer_protocol/mtp_device_manager.h"
6 
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "chromeos/dbus/dbus_thread_manager.h"
10 #include "dbus/bus.h"
11 #include "third_party/cros_system_api/dbus/service_constants.h"
12 
13 namespace device {
14 
15 namespace {
16 
17 #if DCHECK_IS_ON()
18 MtpDeviceManager* g_mtp_device_manager = nullptr;
19 #endif
20 
21 }  // namespace
22 
MtpDeviceManager()23 MtpDeviceManager::MtpDeviceManager()
24     : bus_(chromeos::DBusThreadManager::Get()->GetSystemBus()) {
25   // Listen for future mtpd service owner changes, in case it is not
26   // available right now. There is no guarantee that mtpd is running already.
27   dbus::Bus::ServiceOwnerChangeCallback mtpd_owner_changed_callback =
28       base::BindRepeating(&MtpDeviceManager::FinishSetupOnOriginThread,
29                           weak_ptr_factory_.GetWeakPtr());
30   if (bus_) {
31     bus_->ListenForServiceOwnerChange(mtpd::kMtpdServiceName,
32                                       mtpd_owner_changed_callback);
33     bus_->GetServiceOwner(mtpd::kMtpdServiceName, mtpd_owner_changed_callback);
34   }
35 }
36 
~MtpDeviceManager()37 MtpDeviceManager::~MtpDeviceManager() {
38 #if DCHECK_IS_ON()
39   DCHECK(g_mtp_device_manager);
40   g_mtp_device_manager = nullptr;
41 #endif
42 
43   if (bus_) {
44     bus_->UnlistenForServiceOwnerChange(
45         mtpd::kMtpdServiceName,
46         base::BindRepeating(&MtpDeviceManager::FinishSetupOnOriginThread,
47                             weak_ptr_factory_.GetWeakPtr()));
48   }
49 
50   VLOG(1) << "MtpDeviceManager Shutdown completed";
51 }
52 
AddReceiver(mojo::PendingReceiver<mojom::MtpManager> receiver)53 void MtpDeviceManager::AddReceiver(
54     mojo::PendingReceiver<mojom::MtpManager> receiver) {
55   receivers_.Add(this, std::move(receiver));
56 }
57 
EnumerateStoragesAndSetClient(mojo::PendingAssociatedRemote<mojom::MtpManagerClient> client,EnumerateStoragesAndSetClientCallback callback)58 void MtpDeviceManager::EnumerateStoragesAndSetClient(
59     mojo::PendingAssociatedRemote<mojom::MtpManagerClient> client,
60     EnumerateStoragesAndSetClientCallback callback) {
61   DCHECK(thread_checker_.CalledOnValidThread());
62 
63   // Return all available storage info.
64   std::vector<mojom::MtpStorageInfoPtr> storage_info_ptr_list;
65   storage_info_ptr_list.reserve(storage_info_map_.size());
66   for (const auto& info : storage_info_map_)
67     storage_info_ptr_list.push_back(info.second.Clone());
68   std::move(callback).Run(std::move(storage_info_ptr_list));
69 
70   // Set client.
71   if (!client.is_valid())
72     return;
73 
74   client_.Bind(std::move(client));
75 }
76 
GetStorageInfo(const std::string & storage_name,GetStorageInfoCallback callback)77 void MtpDeviceManager::GetStorageInfo(const std::string& storage_name,
78                                       GetStorageInfoCallback callback) {
79   DCHECK(thread_checker_.CalledOnValidThread());
80   const auto it = storage_info_map_.find(storage_name);
81   mojom::MtpStorageInfoPtr storage_info =
82       it != storage_info_map_.end() ? it->second.Clone() : nullptr;
83   std::move(callback).Run(std::move(storage_info));
84 }
85 
GetStorageInfoFromDevice(const std::string & storage_name,GetStorageInfoFromDeviceCallback callback)86 void MtpDeviceManager::GetStorageInfoFromDevice(
87     const std::string& storage_name,
88     GetStorageInfoFromDeviceCallback callback) {
89   DCHECK(thread_checker_.CalledOnValidThread());
90   if (!base::Contains(storage_info_map_, storage_name) || !mtp_client_) {
91     std::move(callback).Run(nullptr, true /* error */);
92     return;
93   }
94   get_storage_info_from_device_callbacks_.push(std::move(callback));
95   mtp_client_->GetStorageInfoFromDevice(
96       storage_name,
97       base::BindOnce(&MtpDeviceManager::OnGetStorageInfoFromDevice,
98                      weak_ptr_factory_.GetWeakPtr()),
99       base::BindOnce(&MtpDeviceManager::OnGetStorageInfoFromDeviceError,
100                      weak_ptr_factory_.GetWeakPtr()));
101 }
102 
OpenStorage(const std::string & storage_name,const std::string & mode,OpenStorageCallback callback)103 void MtpDeviceManager::OpenStorage(const std::string& storage_name,
104                                    const std::string& mode,
105                                    OpenStorageCallback callback) {
106   DCHECK(thread_checker_.CalledOnValidThread());
107   if (!base::Contains(storage_info_map_, storage_name) || !mtp_client_) {
108     std::move(callback).Run(std::string(), true);
109     return;
110   }
111   open_storage_callbacks_.push(std::move(callback));
112   mtp_client_->OpenStorage(storage_name, mode,
113                            base::BindOnce(&MtpDeviceManager::OnOpenStorage,
114                                           weak_ptr_factory_.GetWeakPtr()),
115                            base::BindOnce(&MtpDeviceManager::OnOpenStorageError,
116                                           weak_ptr_factory_.GetWeakPtr()));
117 }
118 
CloseStorage(const std::string & storage_handle,CloseStorageCallback callback)119 void MtpDeviceManager::CloseStorage(const std::string& storage_handle,
120                                     CloseStorageCallback callback) {
121   DCHECK(thread_checker_.CalledOnValidThread());
122   if (!base::Contains(handles_, storage_handle) || !mtp_client_) {
123     std::move(callback).Run(true);
124     return;
125   }
126   close_storage_callbacks_.push(
127       std::make_pair(std::move(callback), storage_handle));
128   mtp_client_->CloseStorage(
129       storage_handle,
130       base::BindOnce(&MtpDeviceManager::OnCloseStorage,
131                      weak_ptr_factory_.GetWeakPtr()),
132       base::BindOnce(&MtpDeviceManager::OnCloseStorageError,
133                      weak_ptr_factory_.GetWeakPtr()));
134 }
135 
CreateDirectory(const std::string & storage_handle,uint32_t parent_id,const std::string & directory_name,CreateDirectoryCallback callback)136 void MtpDeviceManager::CreateDirectory(const std::string& storage_handle,
137                                        uint32_t parent_id,
138                                        const std::string& directory_name,
139                                        CreateDirectoryCallback callback) {
140   DCHECK(thread_checker_.CalledOnValidThread());
141   if (!base::Contains(handles_, storage_handle) || !mtp_client_) {
142     std::move(callback).Run(true /* error */);
143     return;
144   }
145   create_directory_callbacks_.push(std::move(callback));
146   mtp_client_->CreateDirectory(
147       storage_handle, parent_id, directory_name,
148       base::BindOnce(&MtpDeviceManager::OnCreateDirectory,
149                      weak_ptr_factory_.GetWeakPtr()),
150       base::BindOnce(&MtpDeviceManager::OnCreateDirectoryError,
151                      weak_ptr_factory_.GetWeakPtr()));
152 }
153 
ReadDirectoryEntryIds(const std::string & storage_handle,uint32_t file_id,ReadDirectoryEntryIdsCallback callback)154 void MtpDeviceManager::ReadDirectoryEntryIds(
155     const std::string& storage_handle,
156     uint32_t file_id,
157     ReadDirectoryEntryIdsCallback callback) {
158   DCHECK(thread_checker_.CalledOnValidThread());
159   if (!base::Contains(handles_, storage_handle) || !mtp_client_) {
160     std::move(callback).Run(std::vector<uint32_t>(), /*error=*/true);
161     return;
162   }
163   read_directory_callbacks_.push(std::move(callback));
164   mtp_client_->ReadDirectoryEntryIds(
165       storage_handle, file_id,
166       base::BindOnce(&MtpDeviceManager::OnReadDirectoryEntryIds,
167                      weak_ptr_factory_.GetWeakPtr()),
168       base::BindOnce(&MtpDeviceManager::OnReadDirectoryError,
169                      weak_ptr_factory_.GetWeakPtr()));
170 }
171 
ReadFileChunk(const std::string & storage_handle,uint32_t file_id,uint32_t offset,uint32_t count,ReadFileChunkCallback callback)172 void MtpDeviceManager::ReadFileChunk(const std::string& storage_handle,
173                                      uint32_t file_id,
174                                      uint32_t offset,
175                                      uint32_t count,
176                                      ReadFileChunkCallback callback) {
177   DCHECK(thread_checker_.CalledOnValidThread());
178   if (!base::Contains(handles_, storage_handle) || !mtp_client_) {
179     std::move(callback).Run(std::string(), true);
180     return;
181   }
182   read_file_callbacks_.push(std::move(callback));
183   mtp_client_->ReadFileChunk(storage_handle, file_id, offset, count,
184                              base::BindOnce(&MtpDeviceManager::OnReadFile,
185                                             weak_ptr_factory_.GetWeakPtr()),
186                              base::BindOnce(&MtpDeviceManager::OnReadFileError,
187                                             weak_ptr_factory_.GetWeakPtr()));
188 }
189 
GetFileInfo(const std::string & storage_handle,const std::vector<uint32_t> & file_ids,GetFileInfoCallback callback)190 void MtpDeviceManager::GetFileInfo(const std::string& storage_handle,
191                                    const std::vector<uint32_t>& file_ids,
192                                    GetFileInfoCallback callback) {
193   DCHECK(thread_checker_.CalledOnValidThread());
194   if (!base::Contains(handles_, storage_handle) || !mtp_client_) {
195     std::move(callback).Run(std::vector<device::mojom::MtpFileEntryPtr>(),
196                             /*error=*/true);
197     return;
198   }
199   get_file_info_callbacks_.push(std::move(callback));
200   mtp_client_->GetFileInfo(storage_handle, file_ids,
201                            base::BindOnce(&MtpDeviceManager::OnGetFileInfo,
202                                           weak_ptr_factory_.GetWeakPtr()),
203                            base::BindOnce(&MtpDeviceManager::OnGetFileInfoError,
204                                           weak_ptr_factory_.GetWeakPtr()));
205 }
206 
RenameObject(const std::string & storage_handle,uint32_t object_id,const std::string & new_name,RenameObjectCallback callback)207 void MtpDeviceManager::RenameObject(const std::string& storage_handle,
208                                     uint32_t object_id,
209                                     const std::string& new_name,
210                                     RenameObjectCallback callback) {
211   DCHECK(thread_checker_.CalledOnValidThread());
212   if (!base::Contains(handles_, storage_handle) || !mtp_client_) {
213     std::move(callback).Run(true /* error */);
214     return;
215   }
216   rename_object_callbacks_.push(std::move(callback));
217   mtp_client_->RenameObject(
218       storage_handle, object_id, new_name,
219       base::BindOnce(&MtpDeviceManager::OnRenameObject,
220                      weak_ptr_factory_.GetWeakPtr()),
221       base::BindOnce(&MtpDeviceManager::OnRenameObjectError,
222                      weak_ptr_factory_.GetWeakPtr()));
223 }
224 
CopyFileFromLocal(const std::string & storage_handle,int64_t source_file_descriptor,uint32_t parent_id,const std::string & file_name,CopyFileFromLocalCallback callback)225 void MtpDeviceManager::CopyFileFromLocal(const std::string& storage_handle,
226                                          int64_t source_file_descriptor,
227                                          uint32_t parent_id,
228                                          const std::string& file_name,
229                                          CopyFileFromLocalCallback callback) {
230   DCHECK(thread_checker_.CalledOnValidThread());
231   if (!base::Contains(handles_, storage_handle) || !mtp_client_) {
232     std::move(callback).Run(true /* error */);
233     return;
234   }
235   copy_file_from_local_callbacks_.push(std::move(callback));
236   mtp_client_->CopyFileFromLocal(
237       storage_handle, source_file_descriptor, parent_id, file_name,
238       base::BindOnce(&MtpDeviceManager::OnCopyFileFromLocal,
239                      weak_ptr_factory_.GetWeakPtr()),
240       base::BindOnce(&MtpDeviceManager::OnCopyFileFromLocalError,
241                      weak_ptr_factory_.GetWeakPtr()));
242 }
243 
DeleteObject(const std::string & storage_handle,uint32_t object_id,DeleteObjectCallback callback)244 void MtpDeviceManager::DeleteObject(const std::string& storage_handle,
245                                     uint32_t object_id,
246                                     DeleteObjectCallback callback) {
247   DCHECK(thread_checker_.CalledOnValidThread());
248   if (!base::Contains(handles_, storage_handle) || !mtp_client_) {
249     std::move(callback).Run(true /* error */);
250     return;
251   }
252   delete_object_callbacks_.push(std::move(callback));
253   mtp_client_->DeleteObject(
254       storage_handle, object_id,
255       base::BindOnce(&MtpDeviceManager::OnDeleteObject,
256                      weak_ptr_factory_.GetWeakPtr()),
257       base::BindOnce(&MtpDeviceManager::OnDeleteObjectError,
258                      weak_ptr_factory_.GetWeakPtr()));
259 }
260 
261 // private methods
OnStorageAttached(const std::string & storage_name)262 void MtpDeviceManager::OnStorageAttached(const std::string& storage_name) {
263   DCHECK(thread_checker_.CalledOnValidThread());
264   mtp_client_->GetStorageInfo(
265       storage_name,
266       base::BindOnce(&MtpDeviceManager::OnGetStorageInfo,
267                      weak_ptr_factory_.GetWeakPtr()),
268       base::DoNothing::Once());
269 }
270 
OnStorageDetached(const std::string & storage_name)271 void MtpDeviceManager::OnStorageDetached(const std::string& storage_name) {
272   DCHECK(thread_checker_.CalledOnValidThread());
273   if (storage_info_map_.erase(storage_name) == 0) {
274     // This can happen for a storage where
275     // MediaTransferProtocolDaemonClient::GetStorageInfo() failed.
276     // Return to avoid giving client phantom detach events.
277     return;
278   }
279 
280   // Notify the bound MtpManagerClient.
281   if (client_) {
282     client_->StorageDetached(storage_name);
283   }
284 }
285 
OnStorageChanged(bool is_attach,const std::string & storage_name)286 void MtpDeviceManager::OnStorageChanged(bool is_attach,
287                                         const std::string& storage_name) {
288   DCHECK(thread_checker_.CalledOnValidThread());
289   DCHECK(mtp_client_);
290   if (is_attach)
291     OnStorageAttached(storage_name);
292   else
293     OnStorageDetached(storage_name);
294 }
295 
OnEnumerateStorages(const std::vector<std::string> & storage_names)296 void MtpDeviceManager::OnEnumerateStorages(
297     const std::vector<std::string>& storage_names) {
298   DCHECK(thread_checker_.CalledOnValidThread());
299   DCHECK(mtp_client_);
300   for (const auto& name : storage_names) {
301     if (base::Contains(storage_info_map_, name)) {
302       // OnStorageChanged() might have gotten called first.
303       continue;
304     }
305     OnStorageAttached(name);
306   }
307 }
308 
OnGetStorageInfo(const mojom::MtpStorageInfo & storage_info)309 void MtpDeviceManager::OnGetStorageInfo(
310     const mojom::MtpStorageInfo& storage_info) {
311   DCHECK(thread_checker_.CalledOnValidThread());
312   const std::string& storage_name = storage_info.storage_name;
313   if (base::Contains(storage_info_map_, storage_name)) {
314     // This should not happen, since MtpDeviceManager should
315     // only call EnumerateStorages() once, which populates |storage_info_map_|
316     // with the already-attached devices.
317     // After that, all incoming signals are either for new storage
318     // attachments, which should not be in |storage_info_map_|, or for
319     // storage detachments, which do not add to |storage_info_map_|.
320     // Return to avoid giving client phantom detach events.
321     NOTREACHED();
322     return;
323   }
324 
325   // New storage. Add it and let the bound client know.
326   storage_info_map_.insert(std::make_pair(storage_name, storage_info));
327 
328   if (client_) {
329     client_->StorageAttached(storage_info.Clone());
330   }
331 }
332 
OnGetStorageInfoFromDevice(const mojom::MtpStorageInfo & storage_info)333 void MtpDeviceManager::OnGetStorageInfoFromDevice(
334     const mojom::MtpStorageInfo& storage_info) {
335   std::move(get_storage_info_from_device_callbacks_.front())
336       .Run(storage_info.Clone(), false /* no error */);
337   get_storage_info_from_device_callbacks_.pop();
338 }
339 
OnGetStorageInfoFromDeviceError()340 void MtpDeviceManager::OnGetStorageInfoFromDeviceError() {
341   std::move(get_storage_info_from_device_callbacks_.front())
342       .Run(nullptr, true /* error */);
343   get_storage_info_from_device_callbacks_.pop();
344 }
345 
OnOpenStorage(const std::string & handle)346 void MtpDeviceManager::OnOpenStorage(const std::string& handle) {
347   DCHECK(thread_checker_.CalledOnValidThread());
348   if (!base::Contains(handles_, handle)) {
349     handles_.insert(handle);
350     std::move(open_storage_callbacks_.front()).Run(handle, false);
351   } else {
352     NOTREACHED();
353     std::move(open_storage_callbacks_.front()).Run(std::string(), true);
354   }
355   open_storage_callbacks_.pop();
356 }
357 
OnOpenStorageError()358 void MtpDeviceManager::OnOpenStorageError() {
359   std::move(open_storage_callbacks_.front()).Run(std::string(), true);
360   open_storage_callbacks_.pop();
361 }
362 
OnCloseStorage()363 void MtpDeviceManager::OnCloseStorage() {
364   DCHECK(thread_checker_.CalledOnValidThread());
365   const std::string& handle = close_storage_callbacks_.front().second;
366   if (base::Contains(handles_, handle)) {
367     handles_.erase(handle);
368     std::move(close_storage_callbacks_.front().first).Run(false);
369   } else {
370     NOTREACHED();
371     std::move(close_storage_callbacks_.front().first).Run(true);
372   }
373   close_storage_callbacks_.pop();
374 }
375 
OnCloseStorageError()376 void MtpDeviceManager::OnCloseStorageError() {
377   DCHECK(thread_checker_.CalledOnValidThread());
378   std::move(close_storage_callbacks_.front()).first.Run(true);
379   close_storage_callbacks_.pop();
380 }
381 
OnCreateDirectory()382 void MtpDeviceManager::OnCreateDirectory() {
383   DCHECK(thread_checker_.CalledOnValidThread());
384   std::move(create_directory_callbacks_.front()).Run(false /* no error */);
385   create_directory_callbacks_.pop();
386 }
387 
OnCreateDirectoryError()388 void MtpDeviceManager::OnCreateDirectoryError() {
389   DCHECK(thread_checker_.CalledOnValidThread());
390   std::move(create_directory_callbacks_.front()).Run(true /* error */);
391   create_directory_callbacks_.pop();
392 }
393 
OnReadDirectoryEntryIds(const std::vector<uint32_t> & file_ids)394 void MtpDeviceManager::OnReadDirectoryEntryIds(
395     const std::vector<uint32_t>& file_ids) {
396   DCHECK(thread_checker_.CalledOnValidThread());
397   std::move(read_directory_callbacks_.front()).Run(file_ids, /*error=*/false);
398   read_directory_callbacks_.pop();
399 }
400 
OnReadDirectoryError()401 void MtpDeviceManager::OnReadDirectoryError() {
402   DCHECK(thread_checker_.CalledOnValidThread());
403   std::move(read_directory_callbacks_.front())
404       .Run(std::vector<uint32_t>(), /*error=*/true);
405   read_directory_callbacks_.pop();
406 }
407 
OnReadFile(const std::string & data)408 void MtpDeviceManager::OnReadFile(const std::string& data) {
409   DCHECK(thread_checker_.CalledOnValidThread());
410   std::move(read_file_callbacks_.front()).Run(data, false);
411   read_file_callbacks_.pop();
412 }
413 
OnReadFileError()414 void MtpDeviceManager::OnReadFileError() {
415   DCHECK(thread_checker_.CalledOnValidThread());
416   std::move(read_file_callbacks_.front()).Run(std::string(), true);
417   read_file_callbacks_.pop();
418 }
419 
OnGetFileInfo(const std::vector<mojom::MtpFileEntry> & entries)420 void MtpDeviceManager::OnGetFileInfo(
421     const std::vector<mojom::MtpFileEntry>& entries) {
422   DCHECK(thread_checker_.CalledOnValidThread());
423 
424   std::vector<device::mojom::MtpFileEntryPtr> ret(entries.size());
425   for (size_t i = 0; i < entries.size(); ++i)
426     ret[i] = entries[i].Clone();
427   std::move(get_file_info_callbacks_.front())
428       .Run(std::move(ret), /*error=*/false);
429   get_file_info_callbacks_.pop();
430 }
431 
OnGetFileInfoError()432 void MtpDeviceManager::OnGetFileInfoError() {
433   DCHECK(thread_checker_.CalledOnValidThread());
434   std::move(get_file_info_callbacks_.front())
435       .Run(std::vector<device::mojom::MtpFileEntryPtr>(), /*error=*/true);
436   get_file_info_callbacks_.pop();
437 }
438 
OnRenameObject()439 void MtpDeviceManager::OnRenameObject() {
440   DCHECK(thread_checker_.CalledOnValidThread());
441   std::move(rename_object_callbacks_.front()).Run(false /* no error */);
442   rename_object_callbacks_.pop();
443 }
444 
OnRenameObjectError()445 void MtpDeviceManager::OnRenameObjectError() {
446   DCHECK(thread_checker_.CalledOnValidThread());
447   std::move(rename_object_callbacks_.front()).Run(true /* error */);
448   rename_object_callbacks_.pop();
449 }
450 
OnCopyFileFromLocal()451 void MtpDeviceManager::OnCopyFileFromLocal() {
452   DCHECK(thread_checker_.CalledOnValidThread());
453   std::move(copy_file_from_local_callbacks_.front()).Run(false /* no error */);
454   copy_file_from_local_callbacks_.pop();
455 }
456 
OnCopyFileFromLocalError()457 void MtpDeviceManager::OnCopyFileFromLocalError() {
458   DCHECK(thread_checker_.CalledOnValidThread());
459   std::move(copy_file_from_local_callbacks_.front()).Run(true /* error */);
460   copy_file_from_local_callbacks_.pop();
461 }
462 
OnDeleteObject()463 void MtpDeviceManager::OnDeleteObject() {
464   DCHECK(thread_checker_.CalledOnValidThread());
465   std::move(delete_object_callbacks_.front()).Run(false /* no error */);
466   delete_object_callbacks_.pop();
467 }
468 
OnDeleteObjectError()469 void MtpDeviceManager::OnDeleteObjectError() {
470   DCHECK(thread_checker_.CalledOnValidThread());
471   std::move(delete_object_callbacks_.front()).Run(true /* error */);
472   delete_object_callbacks_.pop();
473 }
474 
FinishSetupOnOriginThread(const std::string & mtpd_service_owner)475 void MtpDeviceManager::FinishSetupOnOriginThread(
476     const std::string& mtpd_service_owner) {
477   DCHECK(thread_checker_.CalledOnValidThread());
478 
479   if (mtpd_service_owner == current_mtpd_owner_)
480     return;
481 
482   // In the case of a new service owner, clear |storage_info_map_|.
483   // Assume all storages have been disconnected. If there is a new service
484   // owner, reconnecting to it will reconnect all the storages as well.
485 
486   // Save a copy of |storage_info_map_| keys as |storage_info_map_| can
487   // change in OnStorageDetached().
488   std::vector<std::string> storage_names;
489   storage_names.reserve(storage_info_map_.size());
490   for (const auto& info : storage_info_map_)
491     storage_names.push_back(info.first);
492 
493   for (const auto& name : storage_names)
494     OnStorageDetached(name);
495 
496   if (mtpd_service_owner.empty()) {
497     current_mtpd_owner_.clear();
498     mtp_client_.reset();
499     return;
500   }
501 
502   current_mtpd_owner_ = mtpd_service_owner;
503 
504   // |bus_| must be valid here. Otherwise, how did this method get called as a
505   // callback in the first place?
506   DCHECK(bus_);
507   mtp_client_ = MediaTransferProtocolDaemonClient::Create(bus_.get());
508 
509   // Set up signals and start initializing |storage_info_map_|.
510   mtp_client_->ListenForChanges(base::BindRepeating(
511       &MtpDeviceManager::OnStorageChanged, weak_ptr_factory_.GetWeakPtr()));
512   mtp_client_->EnumerateStorages(
513       base::BindOnce(&MtpDeviceManager::OnEnumerateStorages,
514                      weak_ptr_factory_.GetWeakPtr()),
515       base::DoNothing::Once());
516 }
517 
518 // static
Initialize()519 std::unique_ptr<MtpDeviceManager> MtpDeviceManager::Initialize() {
520   auto manager = std::make_unique<MtpDeviceManager>();
521 
522   VLOG(1) << "MtpDeviceManager initialized";
523 
524 #if DCHECK_IS_ON()
525   DCHECK(!g_mtp_device_manager);
526   g_mtp_device_manager = manager.get();
527 #endif
528 
529   return manager;
530 }
531 
532 }  // namespace device
533