NaCl: Update revision in DEPS, r12770 -> r12773
[chromium-blink-merge.git] / chrome / browser / media_galleries / media_file_system_registry.cc
blob9b1ab4525514eb238f5b6a498cf716244a4601be
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/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;
48 namespace {
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 {
59 public:
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);
75 private:
76 class RPHWebContentsObserver : public content::WebContentsObserver {
77 public:
78 RPHWebContentsObserver(RPHReferenceManager* manager,
79 WebContents* web_contents);
81 private:
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 {
91 public:
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;
101 private:
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() {
129 Reset();
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;
139 } else {
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),
150 manager_(manager) {
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)
161 return;
163 manager_->OnWebContentsDestroyedOrNavigated(web_contents());
166 RPHReferenceManager::RPHObserver::RPHObserver(
167 RPHReferenceManager* manager, RenderProcessHost* host)
168 : manager_(manager),
169 host_(host) {
170 host->AddObserver(this);
173 RPHReferenceManager::RPHObserver::~RPHObserver() {
174 STLDeleteValues(&observed_web_contentses_);
175 if (host_)
176 host_->RemoveObserver(this);
179 void RPHReferenceManager::RPHObserver::AddWebContentsObserver(
180 WebContents* web_contents) {
181 if (ContainsKey(observed_web_contentses_, web_contents))
182 return;
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) {
200 host_ = NULL;
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
209 // renderer crashes.
210 if (rph_info == observer_map_.end()) {
211 NOTREACHED();
212 return;
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);
231 } // namespace
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,
238 bool removable,
239 bool media_device)
240 : name(fs_name),
241 path(fs_path),
242 fsid(filesystem_id),
243 pref_id(pref_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> {
257 public:
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();
280 ++id) {
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())
292 return;
294 file_system_context_->RevokeFileSystem(gallery->second.fsid);
295 pref_id_map_.erase(gallery);
297 if (pref_id_map_.empty()) {
298 rph_refs_.Reset();
299 CleanUp();
303 // Indicate that the passed |rvh| will reference the file system ids created
304 // by this class.
305 void ReferenceFromRVH(const content::RenderViewHost* rvh) {
306 rph_refs_.ReferenceFromRVH(rvh);
309 private:
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);
332 return;
335 for (std::set<MediaGalleryPrefId>::const_iterator pref_id_it =
336 galleries.begin();
337 pref_id_it != galleries.end();
338 ++pref_id_it) {
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))
344 continue;
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);
350 continue;
353 base::FilePath path = gallery_info.AbsolutePath();
354 if (!MediaStorageUtil::CanCreateFileSystem(device_id, path))
355 continue;
357 std::string fsid =
358 file_system_context_->RegisterFileSystem(device_id, path);
359 if (fsid.empty())
360 continue;
362 MediaFileSystemInfo new_entry(
363 gallery_info.GetGalleryDisplayName(),
364 path,
365 fsid,
366 pref_id,
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) {
375 rph_refs_.Reset();
376 CleanUp();
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);
390 void CleanUp() {
391 DCHECK(rph_refs_.empty());
392 for (PrefIdFsInfoMap::const_iterator it = pref_id_map_.begin();
393 it != pref_id_map_.end();
394 ++it) {
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);
419 /******************
420 * Public methods
421 ******************/
423 void MediaFileSystemRegistry::GetMediaFileSystemsForExtension(
424 const content::RenderViewHost* rvh,
425 const extensions::Extension* extension,
426 const MediaFileSystemsCallback& callback) {
427 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
429 Profile* profile =
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>());
437 return;
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),
452 profile,
453 extension->id()));
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(),
461 callback);
464 MediaGalleriesPreferences* MediaFileSystemRegistry::GetPreferences(
465 Profile* profile) {
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
488 // a second step.
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();
494 ++profile_it) {
495 MediaGalleriesPreferences* preferences = GetPreferences(profile_it->first);
496 // If |preferences| is not yet initialized, it won't contain any galleries.
497 if (!preferences->IsInitialized())
498 continue;
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();
523 ++pref_id_it) {
524 (*extension_host_it)->RevokeGalleryByPrefId(*pref_id_it);
530 /******************
531 * Private methods
532 ******************/
534 class MediaFileSystemRegistry::MediaFileSystemContextImpl
535 : public MediaFileSystemContext {
536 public:
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);
547 } else {
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))
556 return;
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()),
564 fsid));
567 private:
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.
583 std::string fsid;
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(
592 path);
593 } else if (StorageInfo::IsIPhotoDevice(device_id)) {
594 ImportedMediaGalleryRegistry* imported_registry =
595 ImportedMediaGalleryRegistry::GetInstance();
596 fsid = imported_registry->RegisterIPhotoFilesystemOnUIThread(
597 path);
598 } else {
599 std::string fs_name(extension_misc::kMediaFileSystemPathPart);
600 fsid = IsolatedContext::GetInstance()->RegisterFileSystemForPath(
601 fileapi::kFileSystemTypeNativeMedia, path, &fs_name);
603 return fsid;
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));
623 return 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())
657 return;
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
666 // |profile|.
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();
683 ++it) {
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))
688 break;
689 ExtensionHostMap::const_iterator gallery_host_it =
690 extension_host_map.find(extensions[i]->id());
691 if (gallery_host_it == extension_host_map.end())
692 continue;
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
711 // previously used.
712 MediaGalleriesPreferences* preferences = GetPreferences(profile);
713 preferences->RemoveGalleryChangeObserver(this);