Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / media_galleries / media_file_system_registry.cc
blob6102cdd613ba408a7c81f42d2a16e5363ef0813a
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.
5 #include "chrome/browser/media_galleries/media_file_system_registry.h"
7 #include <set>
8 #include <vector>
10 #include "base/bind.h"
11 #include "base/callback.h"
12 #include "base/files/file_path.h"
13 #include "base/prefs/pref_service.h"
14 #include "base/stl_util.h"
15 #include "chrome/browser/extensions/extension_service.h"
16 #include "chrome/browser/extensions/extension_system.h"
17 #include "chrome/browser/media_galleries/fileapi/mtp_device_map_service.h"
18 #include "chrome/browser/media_galleries/imported_media_gallery_registry.h"
19 #include "chrome/browser/media_galleries/media_file_system_context.h"
20 #include "chrome/browser/media_galleries/media_galleries_dialog_controller.h"
21 #include "chrome/browser/media_galleries/media_galleries_histograms.h"
22 #include "chrome/browser/media_galleries/media_galleries_preferences_factory.h"
23 #include "chrome/browser/profiles/profile.h"
24 #include "chrome/browser/storage_monitor/media_storage_util.h"
25 #include "chrome/browser/storage_monitor/storage_monitor.h"
26 #include "chrome/common/chrome_paths.h"
27 #include "chrome/common/extensions/extension_constants.h"
28 #include "chrome/common/pref_names.h"
29 #include "content/public/browser/browser_thread.h"
30 #include "content/public/browser/navigation_details.h"
31 #include "content/public/browser/render_process_host.h"
32 #include "content/public/browser/render_process_host_observer.h"
33 #include "content/public/browser/render_view_host.h"
34 #include "content/public/browser/web_contents.h"
35 #include "content/public/browser/web_contents_observer.h"
36 #include "extensions/common/extension.h"
37 #include "extensions/common/extension_set.h"
38 #include "webkit/browser/fileapi/isolated_context.h"
39 #include "webkit/common/fileapi/file_system_types.h"
41 using content::BrowserThread;
42 using content::NavigationController;
43 using content::RenderProcessHost;
44 using content::WebContents;
45 using fileapi::IsolatedContext;
47 namespace {
49 struct InvalidatedGalleriesInfo {
50 std::set<ExtensionGalleriesHost*> extension_hosts;
51 std::set<MediaGalleryPrefId> pref_ids;
54 // Tracks the liveness of multiple RenderProcessHosts that the caller is
55 // interested in. Once all of the RPHs have closed or been destroyed a call
56 // back informs the caller.
57 class RPHReferenceManager {
58 public:
59 // |no_references_callback| is called when the last RenderViewHost reference
60 // goes away. RenderViewHost references are added through ReferenceFromRVH().
61 explicit RPHReferenceManager(const base::Closure& no_references_callback);
62 virtual ~RPHReferenceManager();
64 // Remove all references, but don't call |no_references_callback|.
65 void Reset() { STLDeleteValues(&observer_map_); }
67 // Returns true if there are no references;
68 bool empty() const { return observer_map_.empty(); }
70 // Adds a reference to the passed |rvh|. Calling this multiple times with
71 // the same |rvh| is a no-op.
72 void ReferenceFromRVH(const content::RenderViewHost* rvh);
74 private:
75 class RPHWebContentsObserver : public content::WebContentsObserver {
76 public:
77 RPHWebContentsObserver(RPHReferenceManager* manager,
78 WebContents* web_contents);
80 private:
81 // content::WebContentsObserver
82 virtual void WebContentsDestroyed(WebContents* web_contents) OVERRIDE;
83 virtual void NavigationEntryCommitted(
84 const content::LoadCommittedDetails& load_details) OVERRIDE;
86 RPHReferenceManager* manager_;
89 class RPHObserver : public content::RenderProcessHostObserver {
90 public:
91 RPHObserver(RPHReferenceManager* manager, RenderProcessHost* host);
92 virtual ~RPHObserver();
94 void AddWebContentsObserver(WebContents* web_contents);
95 void RemoveWebContentsObserver(WebContents* web_contents);
96 bool HasWebContentsObservers() {
97 return observed_web_contentses_.size() > 0;
100 private:
101 virtual void RenderProcessHostDestroyed(RenderProcessHost* host) OVERRIDE;
103 RPHReferenceManager* manager_;
104 RenderProcessHost* host_;
105 typedef std::map<WebContents*, RPHWebContentsObserver*> WCObserverMap;
106 WCObserverMap observed_web_contentses_;
108 typedef std::map<const RenderProcessHost*, RPHObserver*> RPHObserverMap;
110 // Handlers for observed events.
111 void OnRenderProcessHostDestroyed(RenderProcessHost* rph);
112 void OnWebContentsDestroyedOrNavigated(WebContents* contents);
114 // A callback to call when the last RVH reference goes away.
115 base::Closure no_references_callback_;
117 // The set of render processes and web contents that may have references to
118 // the file system ids this instance manages.
119 RPHObserverMap observer_map_;
122 RPHReferenceManager::RPHReferenceManager(
123 const base::Closure& no_references_callback)
124 : no_references_callback_(no_references_callback) {
127 RPHReferenceManager::~RPHReferenceManager() {
128 Reset();
131 void RPHReferenceManager::ReferenceFromRVH(const content::RenderViewHost* rvh) {
132 WebContents* contents = WebContents::FromRenderViewHost(rvh);
133 RenderProcessHost* rph = contents->GetRenderProcessHost();
134 RPHObserver* state = NULL;
135 if (!ContainsKey(observer_map_, rph)) {
136 state = new RPHObserver(this, rph);
137 observer_map_[rph] = state;
138 } else {
139 state = observer_map_[rph];
142 state->AddWebContentsObserver(contents);
145 RPHReferenceManager::RPHWebContentsObserver::RPHWebContentsObserver(
146 RPHReferenceManager* manager,
147 WebContents* web_contents)
148 : content::WebContentsObserver(web_contents),
149 manager_(manager) {
152 void RPHReferenceManager::RPHWebContentsObserver::WebContentsDestroyed(
153 WebContents* web_contents) {
154 manager_->OnWebContentsDestroyedOrNavigated(web_contents);
157 void RPHReferenceManager::RPHWebContentsObserver::NavigationEntryCommitted(
158 const content::LoadCommittedDetails& load_details) {
159 if (load_details.is_in_page)
160 return;
162 manager_->OnWebContentsDestroyedOrNavigated(web_contents());
165 RPHReferenceManager::RPHObserver::RPHObserver(
166 RPHReferenceManager* manager, RenderProcessHost* host)
167 : manager_(manager),
168 host_(host) {
169 host->AddObserver(this);
172 RPHReferenceManager::RPHObserver::~RPHObserver() {
173 STLDeleteValues(&observed_web_contentses_);
174 if (host_)
175 host_->RemoveObserver(this);
178 void RPHReferenceManager::RPHObserver::AddWebContentsObserver(
179 WebContents* web_contents) {
180 if (ContainsKey(observed_web_contentses_, web_contents))
181 return;
183 RPHWebContentsObserver* observer =
184 new RPHWebContentsObserver(manager_, web_contents);
185 observed_web_contentses_[web_contents] = observer;
188 void RPHReferenceManager::RPHObserver::RemoveWebContentsObserver(
189 WebContents* web_contents) {
190 WCObserverMap::iterator wco_iter =
191 observed_web_contentses_.find(web_contents);
192 DCHECK(wco_iter != observed_web_contentses_.end());
193 delete wco_iter->second;
194 observed_web_contentses_.erase(wco_iter);
197 void RPHReferenceManager::RPHObserver::RenderProcessHostDestroyed(
198 RenderProcessHost* host) {
199 host_ = NULL;
200 manager_->OnRenderProcessHostDestroyed(host);
203 void RPHReferenceManager::OnRenderProcessHostDestroyed(
204 RenderProcessHost* rph) {
205 RPHObserverMap::iterator rph_info = observer_map_.find(rph);
206 // This could be a potential problem if the RPH is navigated to a page on the
207 // same renderer (triggering OnWebContentsDestroyedOrNavigated()) and then the
208 // renderer crashes.
209 if (rph_info == observer_map_.end()) {
210 NOTREACHED();
211 return;
213 delete rph_info->second;
214 observer_map_.erase(rph_info);
215 if (observer_map_.empty())
216 no_references_callback_.Run();
219 void RPHReferenceManager::OnWebContentsDestroyedOrNavigated(
220 WebContents* contents) {
221 RenderProcessHost* rph = contents->GetRenderProcessHost();
222 RPHObserverMap::iterator rph_info = observer_map_.find(rph);
223 DCHECK(rph_info != observer_map_.end());
225 rph_info->second->RemoveWebContentsObserver(contents);
226 if (!rph_info->second->HasWebContentsObservers())
227 OnRenderProcessHostDestroyed(rph);
230 } // namespace
232 MediaFileSystemInfo::MediaFileSystemInfo(const base::string16& fs_name,
233 const base::FilePath& fs_path,
234 const std::string& filesystem_id,
235 MediaGalleryPrefId pref_id,
236 const std::string& transient_device_id,
237 bool removable,
238 bool media_device)
239 : name(fs_name),
240 path(fs_path),
241 fsid(filesystem_id),
242 pref_id(pref_id),
243 transient_device_id(transient_device_id),
244 removable(removable),
245 media_device(media_device) {
248 MediaFileSystemInfo::MediaFileSystemInfo() {}
249 MediaFileSystemInfo::~MediaFileSystemInfo() {}
251 // The main owner of this class is
252 // |MediaFileSystemRegistry::extension_hosts_map_|, but a callback may
253 // temporarily hold a reference.
254 class ExtensionGalleriesHost
255 : public base::RefCountedThreadSafe<ExtensionGalleriesHost> {
256 public:
257 // |no_references_callback| is called when the last RenderViewHost reference
258 // goes away. RenderViewHost references are added through ReferenceFromRVH().
259 ExtensionGalleriesHost(MediaFileSystemContext* file_system_context,
260 const base::Closure& no_references_callback)
261 : file_system_context_(file_system_context),
262 no_references_callback_(no_references_callback),
263 rph_refs_(base::Bind(&ExtensionGalleriesHost::CleanUp,
264 base::Unretained(this))) {
267 // For each gallery in the list of permitted |galleries|, checks if the
268 // device is attached and if so looks up or creates a file system id and
269 // passes the information needed for the renderer to create those file
270 // system objects to the |callback|.
271 void GetMediaFileSystems(const MediaGalleryPrefIdSet& galleries,
272 const MediaGalleriesPrefInfoMap& galleries_info,
273 const MediaFileSystemsCallback& callback) {
274 // Extract all the device ids so we can make sure they are attached.
275 MediaStorageUtil::DeviceIdSet* device_ids =
276 new MediaStorageUtil::DeviceIdSet;
277 for (std::set<MediaGalleryPrefId>::const_iterator id = galleries.begin();
278 id != galleries.end();
279 ++id) {
280 device_ids->insert(galleries_info.find(*id)->second.device_id);
282 MediaStorageUtil::FilterAttachedDevices(device_ids, base::Bind(
283 &ExtensionGalleriesHost::GetMediaFileSystemsForAttachedDevices, this,
284 base::Owned(device_ids), galleries, galleries_info, callback));
287 void RevokeOldGalleries(const MediaGalleryPrefIdSet& new_galleries) {
288 if (new_galleries.size() == pref_id_map_.size())
289 return;
291 MediaGalleryPrefIdSet old_galleries;
292 for (PrefIdFsInfoMap::const_iterator it = pref_id_map_.begin();
293 it != pref_id_map_.end();
294 ++it) {
295 old_galleries.insert(it->first);
297 MediaGalleryPrefIdSet invalid_galleries =
298 base::STLSetDifference<MediaGalleryPrefIdSet>(old_galleries,
299 new_galleries);
300 for (MediaGalleryPrefIdSet::const_iterator it = invalid_galleries.begin();
301 it != invalid_galleries.end();
302 ++it) {
303 RevokeGalleryByPrefId(*it);
307 // Revoke the file system for |id| if this extension has created one for |id|.
308 void RevokeGalleryByPrefId(MediaGalleryPrefId id) {
309 PrefIdFsInfoMap::iterator gallery = pref_id_map_.find(id);
310 if (gallery == pref_id_map_.end())
311 return;
313 file_system_context_->RevokeFileSystem(gallery->second.fsid);
314 pref_id_map_.erase(gallery);
316 if (pref_id_map_.empty()) {
317 rph_refs_.Reset();
318 CleanUp();
322 // Indicate that the passed |rvh| will reference the file system ids created
323 // by this class.
324 void ReferenceFromRVH(const content::RenderViewHost* rvh) {
325 rph_refs_.ReferenceFromRVH(rvh);
328 private:
329 typedef std::map<MediaGalleryPrefId, MediaFileSystemInfo> PrefIdFsInfoMap;
331 // Private destructor and friend declaration for ref counted implementation.
332 friend class base::RefCountedThreadSafe<ExtensionGalleriesHost>;
334 virtual ~ExtensionGalleriesHost() {
335 DCHECK(rph_refs_.empty());
336 DCHECK(pref_id_map_.empty());
339 void GetMediaFileSystemsForAttachedDevices(
340 const MediaStorageUtil::DeviceIdSet* attached_devices,
341 const MediaGalleryPrefIdSet& galleries,
342 const MediaGalleriesPrefInfoMap& galleries_info,
343 const MediaFileSystemsCallback& callback) {
344 std::vector<MediaFileSystemInfo> result;
346 if (rph_refs_.empty()) {
347 // We're actually in the middle of shutdown, and Filter...() lagging
348 // which can invoke this method interleaved in the destruction callback
349 // sequence and re-populate pref_id_map_.
350 callback.Run(result);
351 return;
354 MediaGalleryPrefIdSet new_galleries;
355 for (std::set<MediaGalleryPrefId>::const_iterator pref_id_it =
356 galleries.begin();
357 pref_id_it != galleries.end();
358 ++pref_id_it) {
359 const MediaGalleryPrefId& pref_id = *pref_id_it;
360 const MediaGalleryPrefInfo& gallery_info =
361 galleries_info.find(pref_id)->second;
362 const std::string& device_id = gallery_info.device_id;
363 if (!ContainsKey(*attached_devices, device_id))
364 continue;
366 PrefIdFsInfoMap::const_iterator existing_info =
367 pref_id_map_.find(pref_id);
368 if (existing_info != pref_id_map_.end()) {
369 result.push_back(existing_info->second);
370 new_galleries.insert(pref_id);
371 continue;
374 base::FilePath path = gallery_info.AbsolutePath();
375 if (!MediaStorageUtil::CanCreateFileSystem(device_id, path))
376 continue;
378 std::string fsid =
379 file_system_context_->RegisterFileSystem(device_id, path);
380 if (fsid.empty())
381 continue;
383 MediaFileSystemInfo new_entry(
384 gallery_info.GetGalleryDisplayName(),
385 path,
386 fsid,
387 pref_id,
388 GetTransientIdForRemovableDeviceId(device_id),
389 StorageInfo::IsRemovableDevice(device_id),
390 StorageInfo::IsMediaDevice(device_id));
391 result.push_back(new_entry);
392 new_galleries.insert(pref_id);
393 pref_id_map_[pref_id] = new_entry;
396 if (result.size() == 0) {
397 rph_refs_.Reset();
398 CleanUp();
399 } else {
400 RevokeOldGalleries(new_galleries);
403 callback.Run(result);
406 std::string GetTransientIdForRemovableDeviceId(const std::string& device_id) {
407 if (!StorageInfo::IsRemovableDevice(device_id))
408 return std::string();
410 return StorageMonitor::GetInstance()->GetTransientIdForDeviceId(device_id);
413 void CleanUp() {
414 DCHECK(rph_refs_.empty());
415 for (PrefIdFsInfoMap::const_iterator it = pref_id_map_.begin();
416 it != pref_id_map_.end();
417 ++it) {
418 file_system_context_->RevokeFileSystem(it->second.fsid);
420 pref_id_map_.clear();
422 no_references_callback_.Run();
425 // MediaFileSystemRegistry owns |this| and |file_system_context_|, so it's
426 // safe to store a raw pointer.
427 MediaFileSystemContext* file_system_context_;
429 // A callback to call when the last RVH reference goes away.
430 base::Closure no_references_callback_;
432 // A map from the gallery preferences id to the file system information.
433 PrefIdFsInfoMap pref_id_map_;
435 // The set of render processes and web contents that may have references to
436 // the file system ids this instance manages.
437 RPHReferenceManager rph_refs_;
439 DISALLOW_COPY_AND_ASSIGN(ExtensionGalleriesHost);
442 /******************
443 * Public methods
444 ******************/
446 void MediaFileSystemRegistry::GetMediaFileSystemsForExtension(
447 const content::RenderViewHost* rvh,
448 const extensions::Extension* extension,
449 const MediaFileSystemsCallback& callback) {
450 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
452 Profile* profile =
453 Profile::FromBrowserContext(rvh->GetProcess()->GetBrowserContext());
454 MediaGalleriesPreferences* preferences = GetPreferences(profile);
455 MediaGalleryPrefIdSet galleries =
456 preferences->GalleriesForExtension(*extension);
458 if (galleries.empty()) {
459 callback.Run(std::vector<MediaFileSystemInfo>());
460 return;
463 ExtensionGalleriesHostMap::iterator extension_hosts =
464 extension_hosts_map_.find(profile);
465 if (extension_hosts->second.empty())
466 preferences->AddGalleryChangeObserver(this);
468 ExtensionGalleriesHost* extension_host =
469 extension_hosts->second[extension->id()].get();
470 if (!extension_host) {
471 extension_host = new ExtensionGalleriesHost(
472 file_system_context_.get(),
473 base::Bind(&MediaFileSystemRegistry::OnExtensionGalleriesHostEmpty,
474 base::Unretained(this),
475 profile,
476 extension->id()));
477 extension_hosts_map_[profile][extension->id()] = extension_host;
479 // This must come before the GetMediaFileSystems call to make sure the
480 // RVH of the context is referenced before the filesystems are retrieved.
481 extension_host->ReferenceFromRVH(rvh);
483 extension_host->GetMediaFileSystems(galleries, preferences->known_galleries(),
484 callback);
487 MediaGalleriesPreferences* MediaFileSystemRegistry::GetPreferences(
488 Profile* profile) {
489 // Create an empty ExtensionHostMap for this profile on first initialization.
490 if (!ContainsKey(extension_hosts_map_, profile))
491 extension_hosts_map_[profile] = ExtensionHostMap();
492 media_galleries::UsageCount(media_galleries::PROFILES_WITH_USAGE);
494 return MediaGalleriesPreferencesFactory::GetForProfile(profile);
497 void MediaFileSystemRegistry::OnRemovableStorageDetached(
498 const StorageInfo& info) {
499 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
501 // Since revoking a gallery in the ExtensionGalleriesHost may cause it
502 // to be removed from the map and therefore invalidate any iterator pointing
503 // to it, this code first copies all the invalid gallery ids and the
504 // extension hosts in which they may appear (per profile) and revoked it in
505 // a second step.
506 std::vector<InvalidatedGalleriesInfo> invalid_galleries_info;
508 for (ExtensionGalleriesHostMap::iterator profile_it =
509 extension_hosts_map_.begin();
510 profile_it != extension_hosts_map_.end();
511 ++profile_it) {
512 MediaGalleriesPreferences* preferences = GetPreferences(profile_it->first);
513 // If |preferences| is not yet initialized, it won't contain any galleries.
514 if (!preferences->IsInitialized())
515 continue;
517 InvalidatedGalleriesInfo invalid_galleries_in_profile;
518 invalid_galleries_in_profile.pref_ids =
519 preferences->LookUpGalleriesByDeviceId(info.device_id());
521 for (ExtensionHostMap::const_iterator extension_host_it =
522 profile_it->second.begin();
523 extension_host_it != profile_it->second.end();
524 ++extension_host_it) {
525 invalid_galleries_in_profile.extension_hosts.insert(
526 extension_host_it->second.get());
529 invalid_galleries_info.push_back(invalid_galleries_in_profile);
532 for (size_t i = 0; i < invalid_galleries_info.size(); i++) {
533 for (std::set<ExtensionGalleriesHost*>::const_iterator extension_host_it =
534 invalid_galleries_info[i].extension_hosts.begin();
535 extension_host_it != invalid_galleries_info[i].extension_hosts.end();
536 ++extension_host_it) {
537 for (std::set<MediaGalleryPrefId>::const_iterator pref_id_it =
538 invalid_galleries_info[i].pref_ids.begin();
539 pref_id_it != invalid_galleries_info[i].pref_ids.end();
540 ++pref_id_it) {
541 (*extension_host_it)->RevokeGalleryByPrefId(*pref_id_it);
547 /******************
548 * Private methods
549 ******************/
551 class MediaFileSystemRegistry::MediaFileSystemContextImpl
552 : public MediaFileSystemContext {
553 public:
554 explicit MediaFileSystemContextImpl(MediaFileSystemRegistry* registry)
555 : registry_(registry) {
556 DCHECK(registry_); // Suppresses unused warning on Android.
558 virtual ~MediaFileSystemContextImpl() {}
560 virtual std::string RegisterFileSystem(
561 const std::string& device_id, const base::FilePath& path) OVERRIDE {
562 if (StorageInfo::IsMassStorageDevice(device_id)) {
563 return RegisterFileSystemForMassStorage(device_id, path);
564 } else {
565 return RegisterFileSystemForMTPDevice(device_id, path);
569 virtual void RevokeFileSystem(const std::string& fsid) OVERRIDE {
570 ImportedMediaGalleryRegistry* imported_registry =
571 ImportedMediaGalleryRegistry::GetInstance();
572 if (imported_registry->RevokeImportedFilesystemOnUIThread(fsid))
573 return;
575 IsolatedContext::GetInstance()->RevokeFileSystem(fsid);
577 content::BrowserThread::PostTask(
578 content::BrowserThread::IO, FROM_HERE, base::Bind(
579 &MTPDeviceMapService::RevokeMTPFileSystem,
580 base::Unretained(MTPDeviceMapService::GetInstance()),
581 fsid));
584 private:
585 // Registers and returns the file system id for the mass storage device
586 // specified by |device_id| and |path|.
587 std::string RegisterFileSystemForMassStorage(
588 const std::string& device_id, const base::FilePath& path) {
589 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
590 DCHECK(StorageInfo::IsMassStorageDevice(device_id));
592 // Sanity checks for |path|.
593 CHECK(path.IsAbsolute());
594 CHECK(!path.ReferencesParent());
596 // TODO(gbillock): refactor ImportedMediaGalleryRegistry to delegate this
597 // call tree, probably by having it figure out by device id what
598 // registration is needed, or having per-device-type handlers at the
599 // next higher level.
600 std::string fsid;
601 if (StorageInfo::IsITunesDevice(device_id)) {
602 ImportedMediaGalleryRegistry* imported_registry =
603 ImportedMediaGalleryRegistry::GetInstance();
604 fsid = imported_registry->RegisterITunesFilesystemOnUIThread(path);
605 } else if (StorageInfo::IsPicasaDevice(device_id)) {
606 ImportedMediaGalleryRegistry* imported_registry =
607 ImportedMediaGalleryRegistry::GetInstance();
608 fsid = imported_registry->RegisterPicasaFilesystemOnUIThread(
609 path);
610 } else if (StorageInfo::IsIPhotoDevice(device_id)) {
611 ImportedMediaGalleryRegistry* imported_registry =
612 ImportedMediaGalleryRegistry::GetInstance();
613 fsid = imported_registry->RegisterIPhotoFilesystemOnUIThread(
614 path);
615 } else {
616 std::string fs_name(extension_misc::kMediaFileSystemPathPart);
617 fsid = IsolatedContext::GetInstance()->RegisterFileSystemForPath(
618 fileapi::kFileSystemTypeNativeMedia, path, &fs_name);
620 return fsid;
623 std::string RegisterFileSystemForMTPDevice(
624 const std::string& device_id, const base::FilePath& path) {
625 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
626 DCHECK(!StorageInfo::IsMassStorageDevice(device_id));
628 // Sanity checks for |path|.
629 CHECK(MediaStorageUtil::CanCreateFileSystem(device_id, path));
630 std::string fs_name(extension_misc::kMediaFileSystemPathPart);
631 const std::string fsid =
632 IsolatedContext::GetInstance()->RegisterFileSystemForPath(
633 fileapi::kFileSystemTypeDeviceMedia, path, &fs_name);
634 CHECK(!fsid.empty());
635 content::BrowserThread::PostTask(
636 content::BrowserThread::IO, FROM_HERE, base::Bind(
637 &MTPDeviceMapService::RegisterMTPFileSystem,
638 base::Unretained(MTPDeviceMapService::GetInstance()),
639 path.value(), fsid));
640 return fsid;
643 MediaFileSystemRegistry* registry_;
645 DISALLOW_COPY_AND_ASSIGN(MediaFileSystemContextImpl);
648 // Constructor in 'private' section because depends on private class definition.
649 MediaFileSystemRegistry::MediaFileSystemRegistry()
650 : file_system_context_(new MediaFileSystemContextImpl(this)) {
651 StorageMonitor::GetInstance()->AddObserver(this);
654 MediaFileSystemRegistry::~MediaFileSystemRegistry() {
655 // TODO(gbillock): This is needed because the unit test uses the
656 // g_browser_process registry. We should create one in the unit test,
657 // and then can remove this.
658 if (StorageMonitor::GetInstance())
659 StorageMonitor::GetInstance()->RemoveObserver(this);
662 void MediaFileSystemRegistry::OnPermissionRemoved(
663 MediaGalleriesPreferences* prefs,
664 const std::string& extension_id,
665 MediaGalleryPrefId pref_id) {
666 Profile* profile = prefs->profile();
667 ExtensionGalleriesHostMap::const_iterator host_map_it =
668 extension_hosts_map_.find(profile);
669 DCHECK(host_map_it != extension_hosts_map_.end());
670 const ExtensionHostMap& extension_host_map = host_map_it->second;
671 ExtensionHostMap::const_iterator gallery_host_it =
672 extension_host_map.find(extension_id);
673 if (gallery_host_it == extension_host_map.end())
674 return;
675 gallery_host_it->second->RevokeGalleryByPrefId(pref_id);
678 void MediaFileSystemRegistry::OnGalleryRemoved(
679 MediaGalleriesPreferences* prefs,
680 MediaGalleryPrefId pref_id) {
681 Profile* profile = prefs->profile();
682 // Get the Extensions, MediaGalleriesPreferences and ExtensionHostMap for
683 // |profile|.
684 const ExtensionService* extension_service =
685 extensions::ExtensionSystem::Get(profile)->extension_service();
686 const extensions::ExtensionSet* extensions_set =
687 extension_service->extensions();
688 ExtensionGalleriesHostMap::const_iterator host_map_it =
689 extension_hosts_map_.find(profile);
690 DCHECK(host_map_it != extension_hosts_map_.end());
691 const ExtensionHostMap& extension_host_map = host_map_it->second;
693 // Go through ExtensionHosts, and remove indicated gallery, if any.
694 // RevokeGalleryByPrefId() may end up deleting from |extension_host_map| and
695 // even delete |extension_host_map| altogether. So do this in two loops to
696 // avoid using an invalidated iterator or deleted map.
697 std::vector<const extensions::Extension*> extensions;
698 for (ExtensionHostMap::const_iterator it = extension_host_map.begin();
699 it != extension_host_map.end();
700 ++it) {
701 extensions.push_back(extensions_set->GetByID(it->first));
703 for (size_t i = 0; i < extensions.size(); ++i) {
704 if (!ContainsKey(extension_hosts_map_, profile))
705 break;
706 ExtensionHostMap::const_iterator gallery_host_it =
707 extension_host_map.find(extensions[i]->id());
708 if (gallery_host_it == extension_host_map.end())
709 continue;
710 gallery_host_it->second->RevokeGalleryByPrefId(pref_id);
714 void MediaFileSystemRegistry::OnExtensionGalleriesHostEmpty(
715 Profile* profile, const std::string& extension_id) {
716 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
718 ExtensionGalleriesHostMap::iterator extension_hosts =
719 extension_hosts_map_.find(profile);
720 DCHECK(extension_hosts != extension_hosts_map_.end());
721 ExtensionHostMap::size_type erase_count =
722 extension_hosts->second.erase(extension_id);
723 DCHECK_EQ(1U, erase_count);
724 if (extension_hosts->second.empty()) {
725 // When a profile has no ExtensionGalleriesHosts left, remove the
726 // matching gallery-change-watcher since it is no longer needed. Leave the
727 // |extension_hosts| entry alone, since it indicates the profile has been
728 // previously used.
729 MediaGalleriesPreferences* preferences = GetPreferences(profile);
730 preferences->RemoveGalleryChangeObserver(this);