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/media_galleries/fileapi/mtp_device_map_service.h"
17 #include "chrome/browser/media_galleries/imported_media_gallery_registry.h"
18 #include "chrome/browser/media_galleries/media_file_system_context.h"
19 #include "chrome/browser/media_galleries/media_galleries_dialog_controller.h"
20 #include "chrome/browser/media_galleries/media_galleries_histograms.h"
21 #include "chrome/browser/media_galleries/media_galleries_preferences_factory.h"
22 #include "chrome/browser/media_galleries/media_scan_manager.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/browser/extension_system.h"
37 #include "extensions/common/extension.h"
38 #include "extensions/common/extension_set.h"
39 #include "webkit/browser/fileapi/isolated_context.h"
40 #include "webkit/common/fileapi/file_system_types.h"
42 using content::BrowserThread
;
43 using content::NavigationController
;
44 using content::RenderProcessHost
;
45 using content::WebContents
;
46 using fileapi::IsolatedContext
;
50 struct InvalidatedGalleriesInfo
{
51 std::set
<ExtensionGalleriesHost
*> extension_hosts
;
52 std::set
<MediaGalleryPrefId
> pref_ids
;
55 // Tracks the liveness of multiple RenderProcessHosts that the caller is
56 // interested in. Once all of the RPHs have closed or been destroyed a call
57 // back informs the caller.
58 class RPHReferenceManager
{
60 // |no_references_callback| is called when the last RenderViewHost reference
61 // goes away. RenderViewHost references are added through ReferenceFromRVH().
62 explicit RPHReferenceManager(const base::Closure
& no_references_callback
);
63 virtual ~RPHReferenceManager();
65 // Remove all references, but don't call |no_references_callback|.
66 void Reset() { STLDeleteValues(&observer_map_
); }
68 // Returns true if there are no references;
69 bool empty() const { return observer_map_
.empty(); }
71 // Adds a reference to the passed |rvh|. Calling this multiple times with
72 // the same |rvh| is a no-op.
73 void ReferenceFromRVH(const content::RenderViewHost
* rvh
);
76 class RPHWebContentsObserver
: public content::WebContentsObserver
{
78 RPHWebContentsObserver(RPHReferenceManager
* manager
,
79 WebContents
* web_contents
);
82 // content::WebContentsObserver
83 virtual void WebContentsDestroyed(WebContents
* web_contents
) OVERRIDE
;
84 virtual void NavigationEntryCommitted(
85 const content::LoadCommittedDetails
& load_details
) OVERRIDE
;
87 RPHReferenceManager
* manager_
;
90 class RPHObserver
: public content::RenderProcessHostObserver
{
92 RPHObserver(RPHReferenceManager
* manager
, RenderProcessHost
* host
);
93 virtual ~RPHObserver();
95 void AddWebContentsObserver(WebContents
* web_contents
);
96 void RemoveWebContentsObserver(WebContents
* web_contents
);
97 bool HasWebContentsObservers() {
98 return observed_web_contentses_
.size() > 0;
102 virtual void RenderProcessHostDestroyed(RenderProcessHost
* host
) OVERRIDE
;
104 RPHReferenceManager
* manager_
;
105 RenderProcessHost
* host_
;
106 typedef std::map
<WebContents
*, RPHWebContentsObserver
*> WCObserverMap
;
107 WCObserverMap observed_web_contentses_
;
109 typedef std::map
<const RenderProcessHost
*, RPHObserver
*> RPHObserverMap
;
111 // Handlers for observed events.
112 void OnRenderProcessHostDestroyed(RenderProcessHost
* rph
);
113 void OnWebContentsDestroyedOrNavigated(WebContents
* contents
);
115 // A callback to call when the last RVH reference goes away.
116 base::Closure no_references_callback_
;
118 // The set of render processes and web contents that may have references to
119 // the file system ids this instance manages.
120 RPHObserverMap observer_map_
;
123 RPHReferenceManager::RPHReferenceManager(
124 const base::Closure
& no_references_callback
)
125 : no_references_callback_(no_references_callback
) {
128 RPHReferenceManager::~RPHReferenceManager() {
132 void RPHReferenceManager::ReferenceFromRVH(const content::RenderViewHost
* rvh
) {
133 WebContents
* contents
= WebContents::FromRenderViewHost(rvh
);
134 RenderProcessHost
* rph
= contents
->GetRenderProcessHost();
135 RPHObserver
* state
= NULL
;
136 if (!ContainsKey(observer_map_
, rph
)) {
137 state
= new RPHObserver(this, rph
);
138 observer_map_
[rph
] = state
;
140 state
= observer_map_
[rph
];
143 state
->AddWebContentsObserver(contents
);
146 RPHReferenceManager::RPHWebContentsObserver::RPHWebContentsObserver(
147 RPHReferenceManager
* manager
,
148 WebContents
* web_contents
)
149 : content::WebContentsObserver(web_contents
),
153 void RPHReferenceManager::RPHWebContentsObserver::WebContentsDestroyed(
154 WebContents
* web_contents
) {
155 manager_
->OnWebContentsDestroyedOrNavigated(web_contents
);
158 void RPHReferenceManager::RPHWebContentsObserver::NavigationEntryCommitted(
159 const content::LoadCommittedDetails
& load_details
) {
160 if (load_details
.is_in_page
)
163 manager_
->OnWebContentsDestroyedOrNavigated(web_contents());
166 RPHReferenceManager::RPHObserver::RPHObserver(
167 RPHReferenceManager
* manager
, RenderProcessHost
* host
)
170 host
->AddObserver(this);
173 RPHReferenceManager::RPHObserver::~RPHObserver() {
174 STLDeleteValues(&observed_web_contentses_
);
176 host_
->RemoveObserver(this);
179 void RPHReferenceManager::RPHObserver::AddWebContentsObserver(
180 WebContents
* web_contents
) {
181 if (ContainsKey(observed_web_contentses_
, web_contents
))
184 RPHWebContentsObserver
* observer
=
185 new RPHWebContentsObserver(manager_
, web_contents
);
186 observed_web_contentses_
[web_contents
] = observer
;
189 void RPHReferenceManager::RPHObserver::RemoveWebContentsObserver(
190 WebContents
* web_contents
) {
191 WCObserverMap::iterator wco_iter
=
192 observed_web_contentses_
.find(web_contents
);
193 DCHECK(wco_iter
!= observed_web_contentses_
.end());
194 delete wco_iter
->second
;
195 observed_web_contentses_
.erase(wco_iter
);
198 void RPHReferenceManager::RPHObserver::RenderProcessHostDestroyed(
199 RenderProcessHost
* host
) {
201 manager_
->OnRenderProcessHostDestroyed(host
);
204 void RPHReferenceManager::OnRenderProcessHostDestroyed(
205 RenderProcessHost
* rph
) {
206 RPHObserverMap::iterator rph_info
= observer_map_
.find(rph
);
207 // This could be a potential problem if the RPH is navigated to a page on the
208 // same renderer (triggering OnWebContentsDestroyedOrNavigated()) and then the
210 if (rph_info
== observer_map_
.end()) {
214 delete rph_info
->second
;
215 observer_map_
.erase(rph_info
);
216 if (observer_map_
.empty())
217 no_references_callback_
.Run();
220 void RPHReferenceManager::OnWebContentsDestroyedOrNavigated(
221 WebContents
* contents
) {
222 RenderProcessHost
* rph
= contents
->GetRenderProcessHost();
223 RPHObserverMap::iterator rph_info
= observer_map_
.find(rph
);
224 DCHECK(rph_info
!= observer_map_
.end());
226 rph_info
->second
->RemoveWebContentsObserver(contents
);
227 if (!rph_info
->second
->HasWebContentsObservers())
228 OnRenderProcessHostDestroyed(rph
);
233 MediaFileSystemInfo::MediaFileSystemInfo(const base::string16
& fs_name
,
234 const base::FilePath
& fs_path
,
235 const std::string
& filesystem_id
,
236 MediaGalleryPrefId pref_id
,
237 const std::string
& transient_device_id
,
244 transient_device_id(transient_device_id
),
245 removable(removable
),
246 media_device(media_device
) {
249 MediaFileSystemInfo::MediaFileSystemInfo() {}
250 MediaFileSystemInfo::~MediaFileSystemInfo() {}
252 // The main owner of this class is
253 // |MediaFileSystemRegistry::extension_hosts_map_|, but a callback may
254 // temporarily hold a reference.
255 class ExtensionGalleriesHost
256 : public base::RefCountedThreadSafe
<ExtensionGalleriesHost
> {
258 // |no_references_callback| is called when the last RenderViewHost reference
259 // goes away. RenderViewHost references are added through ReferenceFromRVH().
260 ExtensionGalleriesHost(MediaFileSystemContext
* file_system_context
,
261 const base::Closure
& no_references_callback
)
262 : file_system_context_(file_system_context
),
263 no_references_callback_(no_references_callback
),
264 rph_refs_(base::Bind(&ExtensionGalleriesHost::CleanUp
,
265 base::Unretained(this))) {
268 // For each gallery in the list of permitted |galleries|, checks if the
269 // device is attached and if so looks up or creates a file system id and
270 // passes the information needed for the renderer to create those file
271 // system objects to the |callback|.
272 void GetMediaFileSystems(const MediaGalleryPrefIdSet
& galleries
,
273 const MediaGalleriesPrefInfoMap
& galleries_info
,
274 const MediaFileSystemsCallback
& callback
) {
275 // Extract all the device ids so we can make sure they are attached.
276 MediaStorageUtil::DeviceIdSet
* device_ids
=
277 new MediaStorageUtil::DeviceIdSet
;
278 for (std::set
<MediaGalleryPrefId
>::const_iterator id
= galleries
.begin();
279 id
!= galleries
.end();
281 device_ids
->insert(galleries_info
.find(*id
)->second
.device_id
);
283 MediaStorageUtil::FilterAttachedDevices(device_ids
, base::Bind(
284 &ExtensionGalleriesHost::GetMediaFileSystemsForAttachedDevices
, this,
285 base::Owned(device_ids
), galleries
, galleries_info
, callback
));
288 // Revoke the file system for |id| if this extension has created one for |id|.
289 void RevokeGalleryByPrefId(MediaGalleryPrefId id
) {
290 PrefIdFsInfoMap::iterator gallery
= pref_id_map_
.find(id
);
291 if (gallery
== pref_id_map_
.end())
294 file_system_context_
->RevokeFileSystem(gallery
->second
.fsid
);
295 pref_id_map_
.erase(gallery
);
297 if (pref_id_map_
.empty()) {
303 // Indicate that the passed |rvh| will reference the file system ids created
305 void ReferenceFromRVH(const content::RenderViewHost
* rvh
) {
306 rph_refs_
.ReferenceFromRVH(rvh
);
310 typedef std::map
<MediaGalleryPrefId
, MediaFileSystemInfo
> PrefIdFsInfoMap
;
312 // Private destructor and friend declaration for ref counted implementation.
313 friend class base::RefCountedThreadSafe
<ExtensionGalleriesHost
>;
315 virtual ~ExtensionGalleriesHost() {
316 DCHECK(rph_refs_
.empty());
317 DCHECK(pref_id_map_
.empty());
320 void GetMediaFileSystemsForAttachedDevices(
321 const MediaStorageUtil::DeviceIdSet
* attached_devices
,
322 const MediaGalleryPrefIdSet
& galleries
,
323 const MediaGalleriesPrefInfoMap
& galleries_info
,
324 const MediaFileSystemsCallback
& callback
) {
325 std::vector
<MediaFileSystemInfo
> result
;
327 if (rph_refs_
.empty()) {
328 // We're actually in the middle of shutdown, and Filter...() lagging
329 // which can invoke this method interleaved in the destruction callback
330 // sequence and re-populate pref_id_map_.
331 callback
.Run(result
);
335 for (std::set
<MediaGalleryPrefId
>::const_iterator pref_id_it
=
337 pref_id_it
!= galleries
.end();
339 const MediaGalleryPrefId
& pref_id
= *pref_id_it
;
340 const MediaGalleryPrefInfo
& gallery_info
=
341 galleries_info
.find(pref_id
)->second
;
342 const std::string
& device_id
= gallery_info
.device_id
;
343 if (!ContainsKey(*attached_devices
, device_id
))
346 PrefIdFsInfoMap::const_iterator existing_info
=
347 pref_id_map_
.find(pref_id
);
348 if (existing_info
!= pref_id_map_
.end()) {
349 result
.push_back(existing_info
->second
);
353 base::FilePath path
= gallery_info
.AbsolutePath();
354 if (!MediaStorageUtil::CanCreateFileSystem(device_id
, path
))
358 file_system_context_
->RegisterFileSystem(device_id
, path
);
362 MediaFileSystemInfo
new_entry(
363 gallery_info
.GetGalleryDisplayName(),
367 GetTransientIdForRemovableDeviceId(device_id
),
368 StorageInfo::IsRemovableDevice(device_id
),
369 StorageInfo::IsMediaDevice(device_id
));
370 result
.push_back(new_entry
);
371 pref_id_map_
[pref_id
] = new_entry
;
374 if (result
.size() == 0) {
379 DCHECK_EQ(pref_id_map_
.size(), result
.size());
380 callback
.Run(result
);
383 std::string
GetTransientIdForRemovableDeviceId(const std::string
& device_id
) {
384 if (!StorageInfo::IsRemovableDevice(device_id
))
385 return std::string();
387 return StorageMonitor::GetInstance()->GetTransientIdForDeviceId(device_id
);
391 DCHECK(rph_refs_
.empty());
392 for (PrefIdFsInfoMap::const_iterator it
= pref_id_map_
.begin();
393 it
!= pref_id_map_
.end();
395 file_system_context_
->RevokeFileSystem(it
->second
.fsid
);
397 pref_id_map_
.clear();
399 no_references_callback_
.Run();
402 // MediaFileSystemRegistry owns |this| and |file_system_context_|, so it's
403 // safe to store a raw pointer.
404 MediaFileSystemContext
* file_system_context_
;
406 // A callback to call when the last RVH reference goes away.
407 base::Closure no_references_callback_
;
409 // A map from the gallery preferences id to the file system information.
410 PrefIdFsInfoMap pref_id_map_
;
412 // The set of render processes and web contents that may have references to
413 // the file system ids this instance manages.
414 RPHReferenceManager rph_refs_
;
416 DISALLOW_COPY_AND_ASSIGN(ExtensionGalleriesHost
);
423 void MediaFileSystemRegistry::GetMediaFileSystemsForExtension(
424 const content::RenderViewHost
* rvh
,
425 const extensions::Extension
* extension
,
426 const MediaFileSystemsCallback
& callback
) {
427 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
430 Profile::FromBrowserContext(rvh
->GetProcess()->GetBrowserContext());
431 MediaGalleriesPreferences
* preferences
= GetPreferences(profile
);
432 MediaGalleryPrefIdSet galleries
=
433 preferences
->GalleriesForExtension(*extension
);
435 if (galleries
.empty()) {
436 callback
.Run(std::vector
<MediaFileSystemInfo
>());
440 ExtensionGalleriesHostMap::iterator extension_hosts
=
441 extension_hosts_map_
.find(profile
);
442 if (extension_hosts
->second
.empty())
443 preferences
->AddGalleryChangeObserver(this);
445 ExtensionGalleriesHost
* extension_host
=
446 extension_hosts
->second
[extension
->id()].get();
447 if (!extension_host
) {
448 extension_host
= new ExtensionGalleriesHost(
449 file_system_context_
.get(),
450 base::Bind(&MediaFileSystemRegistry::OnExtensionGalleriesHostEmpty
,
451 base::Unretained(this),
454 extension_hosts_map_
[profile
][extension
->id()] = extension_host
;
456 // This must come before the GetMediaFileSystems call to make sure the
457 // RVH of the context is referenced before the filesystems are retrieved.
458 extension_host
->ReferenceFromRVH(rvh
);
460 extension_host
->GetMediaFileSystems(galleries
, preferences
->known_galleries(),
464 MediaGalleriesPreferences
* MediaFileSystemRegistry::GetPreferences(
466 // Create an empty ExtensionHostMap for this profile on first initialization.
467 if (!ContainsKey(extension_hosts_map_
, profile
))
468 extension_hosts_map_
[profile
] = ExtensionHostMap();
469 media_galleries::UsageCount(media_galleries::PROFILES_WITH_USAGE
);
471 return MediaGalleriesPreferencesFactory::GetForProfile(profile
);
474 MediaScanManager
* MediaFileSystemRegistry::media_scan_manager() {
475 if (!media_scan_manager_
)
476 media_scan_manager_
.reset(new MediaScanManager
);
477 return media_scan_manager_
.get();
480 void MediaFileSystemRegistry::OnRemovableStorageDetached(
481 const StorageInfo
& info
) {
482 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
484 // Since revoking a gallery in the ExtensionGalleriesHost may cause it
485 // to be removed from the map and therefore invalidate any iterator pointing
486 // to it, this code first copies all the invalid gallery ids and the
487 // extension hosts in which they may appear (per profile) and revoked it in
489 std::vector
<InvalidatedGalleriesInfo
> invalid_galleries_info
;
491 for (ExtensionGalleriesHostMap::iterator profile_it
=
492 extension_hosts_map_
.begin();
493 profile_it
!= extension_hosts_map_
.end();
495 MediaGalleriesPreferences
* preferences
= GetPreferences(profile_it
->first
);
496 // If |preferences| is not yet initialized, it won't contain any galleries.
497 if (!preferences
->IsInitialized())
500 InvalidatedGalleriesInfo invalid_galleries_in_profile
;
501 invalid_galleries_in_profile
.pref_ids
=
502 preferences
->LookUpGalleriesByDeviceId(info
.device_id());
504 for (ExtensionHostMap::const_iterator extension_host_it
=
505 profile_it
->second
.begin();
506 extension_host_it
!= profile_it
->second
.end();
507 ++extension_host_it
) {
508 invalid_galleries_in_profile
.extension_hosts
.insert(
509 extension_host_it
->second
.get());
512 invalid_galleries_info
.push_back(invalid_galleries_in_profile
);
515 for (size_t i
= 0; i
< invalid_galleries_info
.size(); i
++) {
516 for (std::set
<ExtensionGalleriesHost
*>::const_iterator extension_host_it
=
517 invalid_galleries_info
[i
].extension_hosts
.begin();
518 extension_host_it
!= invalid_galleries_info
[i
].extension_hosts
.end();
519 ++extension_host_it
) {
520 for (std::set
<MediaGalleryPrefId
>::const_iterator pref_id_it
=
521 invalid_galleries_info
[i
].pref_ids
.begin();
522 pref_id_it
!= invalid_galleries_info
[i
].pref_ids
.end();
524 (*extension_host_it
)->RevokeGalleryByPrefId(*pref_id_it
);
534 class MediaFileSystemRegistry::MediaFileSystemContextImpl
535 : public MediaFileSystemContext
{
537 explicit MediaFileSystemContextImpl(MediaFileSystemRegistry
* registry
)
538 : registry_(registry
) {
539 DCHECK(registry_
); // Suppresses unused warning on Android.
541 virtual ~MediaFileSystemContextImpl() {}
543 virtual std::string
RegisterFileSystem(
544 const std::string
& device_id
, const base::FilePath
& path
) OVERRIDE
{
545 if (StorageInfo::IsMassStorageDevice(device_id
)) {
546 return RegisterFileSystemForMassStorage(device_id
, path
);
548 return RegisterFileSystemForMTPDevice(device_id
, path
);
552 virtual void RevokeFileSystem(const std::string
& fsid
) OVERRIDE
{
553 ImportedMediaGalleryRegistry
* imported_registry
=
554 ImportedMediaGalleryRegistry::GetInstance();
555 if (imported_registry
->RevokeImportedFilesystemOnUIThread(fsid
))
558 IsolatedContext::GetInstance()->RevokeFileSystem(fsid
);
560 content::BrowserThread::PostTask(
561 content::BrowserThread::IO
, FROM_HERE
, base::Bind(
562 &MTPDeviceMapService::RevokeMTPFileSystem
,
563 base::Unretained(MTPDeviceMapService::GetInstance()),
568 // Registers and returns the file system id for the mass storage device
569 // specified by |device_id| and |path|.
570 std::string
RegisterFileSystemForMassStorage(
571 const std::string
& device_id
, const base::FilePath
& path
) {
572 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
573 DCHECK(StorageInfo::IsMassStorageDevice(device_id
));
575 // Sanity checks for |path|.
576 CHECK(path
.IsAbsolute());
577 CHECK(!path
.ReferencesParent());
579 // TODO(gbillock): refactor ImportedMediaGalleryRegistry to delegate this
580 // call tree, probably by having it figure out by device id what
581 // registration is needed, or having per-device-type handlers at the
582 // next higher level.
584 if (StorageInfo::IsITunesDevice(device_id
)) {
585 ImportedMediaGalleryRegistry
* imported_registry
=
586 ImportedMediaGalleryRegistry::GetInstance();
587 fsid
= imported_registry
->RegisterITunesFilesystemOnUIThread(path
);
588 } else if (StorageInfo::IsPicasaDevice(device_id
)) {
589 ImportedMediaGalleryRegistry
* imported_registry
=
590 ImportedMediaGalleryRegistry::GetInstance();
591 fsid
= imported_registry
->RegisterPicasaFilesystemOnUIThread(
593 } else if (StorageInfo::IsIPhotoDevice(device_id
)) {
594 ImportedMediaGalleryRegistry
* imported_registry
=
595 ImportedMediaGalleryRegistry::GetInstance();
596 fsid
= imported_registry
->RegisterIPhotoFilesystemOnUIThread(
599 std::string
fs_name(extension_misc::kMediaFileSystemPathPart
);
600 fsid
= IsolatedContext::GetInstance()->RegisterFileSystemForPath(
601 fileapi::kFileSystemTypeNativeMedia
, path
, &fs_name
);
606 std::string
RegisterFileSystemForMTPDevice(
607 const std::string
& device_id
, const base::FilePath
& path
) {
608 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
609 DCHECK(!StorageInfo::IsMassStorageDevice(device_id
));
611 // Sanity checks for |path|.
612 CHECK(MediaStorageUtil::CanCreateFileSystem(device_id
, path
));
613 std::string
fs_name(extension_misc::kMediaFileSystemPathPart
);
614 const std::string fsid
=
615 IsolatedContext::GetInstance()->RegisterFileSystemForPath(
616 fileapi::kFileSystemTypeDeviceMedia
, path
, &fs_name
);
617 CHECK(!fsid
.empty());
618 content::BrowserThread::PostTask(
619 content::BrowserThread::IO
, FROM_HERE
, base::Bind(
620 &MTPDeviceMapService::RegisterMTPFileSystem
,
621 base::Unretained(MTPDeviceMapService::GetInstance()),
622 path
.value(), fsid
));
626 MediaFileSystemRegistry
* registry_
;
628 DISALLOW_COPY_AND_ASSIGN(MediaFileSystemContextImpl
);
631 // Constructor in 'private' section because depends on private class definition.
632 MediaFileSystemRegistry::MediaFileSystemRegistry()
633 : file_system_context_(new MediaFileSystemContextImpl(this)) {
634 StorageMonitor::GetInstance()->AddObserver(this);
637 MediaFileSystemRegistry::~MediaFileSystemRegistry() {
638 // TODO(gbillock): This is needed because the unit test uses the
639 // g_browser_process registry. We should create one in the unit test,
640 // and then can remove this.
641 if (StorageMonitor::GetInstance())
642 StorageMonitor::GetInstance()->RemoveObserver(this);
645 void MediaFileSystemRegistry::OnPermissionRemoved(
646 MediaGalleriesPreferences
* prefs
,
647 const std::string
& extension_id
,
648 MediaGalleryPrefId pref_id
) {
649 Profile
* profile
= prefs
->profile();
650 ExtensionGalleriesHostMap::const_iterator host_map_it
=
651 extension_hosts_map_
.find(profile
);
652 DCHECK(host_map_it
!= extension_hosts_map_
.end());
653 const ExtensionHostMap
& extension_host_map
= host_map_it
->second
;
654 ExtensionHostMap::const_iterator gallery_host_it
=
655 extension_host_map
.find(extension_id
);
656 if (gallery_host_it
== extension_host_map
.end())
658 gallery_host_it
->second
->RevokeGalleryByPrefId(pref_id
);
661 void MediaFileSystemRegistry::OnGalleryRemoved(
662 MediaGalleriesPreferences
* prefs
,
663 MediaGalleryPrefId pref_id
) {
664 Profile
* profile
= prefs
->profile();
665 // Get the Extensions, MediaGalleriesPreferences and ExtensionHostMap for
667 const ExtensionService
* extension_service
=
668 extensions::ExtensionSystem::Get(profile
)->extension_service();
669 const extensions::ExtensionSet
* extensions_set
=
670 extension_service
->extensions();
671 ExtensionGalleriesHostMap::const_iterator host_map_it
=
672 extension_hosts_map_
.find(profile
);
673 DCHECK(host_map_it
!= extension_hosts_map_
.end());
674 const ExtensionHostMap
& extension_host_map
= host_map_it
->second
;
676 // Go through ExtensionHosts, and remove indicated gallery, if any.
677 // RevokeGalleryByPrefId() may end up deleting from |extension_host_map| and
678 // even delete |extension_host_map| altogether. So do this in two loops to
679 // avoid using an invalidated iterator or deleted map.
680 std::vector
<const extensions::Extension
*> extensions
;
681 for (ExtensionHostMap::const_iterator it
= extension_host_map
.begin();
682 it
!= extension_host_map
.end();
684 extensions
.push_back(extensions_set
->GetByID(it
->first
));
686 for (size_t i
= 0; i
< extensions
.size(); ++i
) {
687 if (!ContainsKey(extension_hosts_map_
, profile
))
689 ExtensionHostMap::const_iterator gallery_host_it
=
690 extension_host_map
.find(extensions
[i
]->id());
691 if (gallery_host_it
== extension_host_map
.end())
693 gallery_host_it
->second
->RevokeGalleryByPrefId(pref_id
);
697 void MediaFileSystemRegistry::OnExtensionGalleriesHostEmpty(
698 Profile
* profile
, const std::string
& extension_id
) {
699 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
701 ExtensionGalleriesHostMap::iterator extension_hosts
=
702 extension_hosts_map_
.find(profile
);
703 DCHECK(extension_hosts
!= extension_hosts_map_
.end());
704 ExtensionHostMap::size_type erase_count
=
705 extension_hosts
->second
.erase(extension_id
);
706 DCHECK_EQ(1U, erase_count
);
707 if (extension_hosts
->second
.empty()) {
708 // When a profile has no ExtensionGalleriesHosts left, remove the
709 // matching gallery-change-watcher since it is no longer needed. Leave the
710 // |extension_hosts| entry alone, since it indicates the profile has been
712 MediaGalleriesPreferences
* preferences
= GetPreferences(profile
);
713 preferences
->RemoveGalleryChangeObserver(this);