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"
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
;
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
{
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
);
75 class RPHWebContentsObserver
: public content::WebContentsObserver
{
77 RPHWebContentsObserver(RPHReferenceManager
* manager
,
78 WebContents
* web_contents
);
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
{
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;
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() {
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
;
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
),
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
)
162 manager_
->OnWebContentsDestroyedOrNavigated(web_contents());
165 RPHReferenceManager::RPHObserver::RPHObserver(
166 RPHReferenceManager
* manager
, RenderProcessHost
* host
)
169 host
->AddObserver(this);
172 RPHReferenceManager::RPHObserver::~RPHObserver() {
173 STLDeleteValues(&observed_web_contentses_
);
175 host_
->RemoveObserver(this);
178 void RPHReferenceManager::RPHObserver::AddWebContentsObserver(
179 WebContents
* web_contents
) {
180 if (ContainsKey(observed_web_contentses_
, web_contents
))
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
) {
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
209 if (rph_info
== observer_map_
.end()) {
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
);
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
,
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
> {
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();
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())
291 MediaGalleryPrefIdSet old_galleries
;
292 for (PrefIdFsInfoMap::const_iterator it
= pref_id_map_
.begin();
293 it
!= pref_id_map_
.end();
295 old_galleries
.insert(it
->first
);
297 MediaGalleryPrefIdSet invalid_galleries
=
298 base::STLSetDifference
<MediaGalleryPrefIdSet
>(old_galleries
,
300 for (MediaGalleryPrefIdSet::const_iterator it
= invalid_galleries
.begin();
301 it
!= invalid_galleries
.end();
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())
313 file_system_context_
->RevokeFileSystem(gallery
->second
.fsid
);
314 pref_id_map_
.erase(gallery
);
316 if (pref_id_map_
.empty()) {
322 // Indicate that the passed |rvh| will reference the file system ids created
324 void ReferenceFromRVH(const content::RenderViewHost
* rvh
) {
325 rph_refs_
.ReferenceFromRVH(rvh
);
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
);
354 MediaGalleryPrefIdSet new_galleries
;
355 for (std::set
<MediaGalleryPrefId
>::const_iterator pref_id_it
=
357 pref_id_it
!= galleries
.end();
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
))
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
);
374 base::FilePath path
= gallery_info
.AbsolutePath();
375 if (!MediaStorageUtil::CanCreateFileSystem(device_id
, path
))
379 file_system_context_
->RegisterFileSystem(device_id
, path
);
383 MediaFileSystemInfo
new_entry(
384 gallery_info
.GetGalleryDisplayName(),
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) {
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
);
414 DCHECK(rph_refs_
.empty());
415 for (PrefIdFsInfoMap::const_iterator it
= pref_id_map_
.begin();
416 it
!= pref_id_map_
.end();
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
);
446 void MediaFileSystemRegistry::GetMediaFileSystemsForExtension(
447 const content::RenderViewHost
* rvh
,
448 const extensions::Extension
* extension
,
449 const MediaFileSystemsCallback
& callback
) {
450 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
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
>());
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),
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(),
487 MediaGalleriesPreferences
* MediaFileSystemRegistry::GetPreferences(
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
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();
512 MediaGalleriesPreferences
* preferences
= GetPreferences(profile_it
->first
);
513 // If |preferences| is not yet initialized, it won't contain any galleries.
514 if (!preferences
->IsInitialized())
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();
541 (*extension_host_it
)->RevokeGalleryByPrefId(*pref_id_it
);
551 class MediaFileSystemRegistry::MediaFileSystemContextImpl
552 : public MediaFileSystemContext
{
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
);
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
))
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()),
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.
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(
610 } else if (StorageInfo::IsIPhotoDevice(device_id
)) {
611 ImportedMediaGalleryRegistry
* imported_registry
=
612 ImportedMediaGalleryRegistry::GetInstance();
613 fsid
= imported_registry
->RegisterIPhotoFilesystemOnUIThread(
616 std::string
fs_name(extension_misc::kMediaFileSystemPathPart
);
617 fsid
= IsolatedContext::GetInstance()->RegisterFileSystemForPath(
618 fileapi::kFileSystemTypeNativeMedia
, path
, &fs_name
);
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
));
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())
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
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();
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
))
706 ExtensionHostMap::const_iterator gallery_host_it
=
707 extension_host_map
.find(extensions
[i
]->id());
708 if (gallery_host_it
== extension_host_map
.end())
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
729 MediaGalleriesPreferences
* preferences
= GetPreferences(profile
);
730 preferences
->RemoveGalleryChangeObserver(this);