diff options
author | vandebo@chromium.org <vandebo@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-09-07 23:38:01 +0000 |
---|---|---|
committer | vandebo@chromium.org <vandebo@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-09-07 23:38:01 +0000 |
commit | 1a39d73e551b07893d3b7cecb3ef3ac4871d105b (patch) | |
tree | 10fb4e8a0805491d8a4b5a1a9ec98024d1e373db /chrome/browser | |
parent | b785cd36336aac3fc41402066a28363b02bcde0d (diff) | |
download | chromium_src-1a39d73e551b07893d3b7cecb3ef3ac4871d105b.zip chromium_src-1a39d73e551b07893d3b7cecb3ef3ac4871d105b.tar.gz chromium_src-1a39d73e551b07893d3b7cecb3ef3ac4871d105b.tar.bz2 |
Connect MediaFileSystemRegistry with MediaGalleriesPreferences
Refactor MediaFileSystemRegistry to make state easier to manage and connect the extension preferences to the registry.
Review URL: https://chromiumcodereview.appspot.com/10871049
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@155534 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
6 files changed, 378 insertions, 207 deletions
diff --git a/chrome/browser/extensions/api/media_galleries/media_galleries_api.cc b/chrome/browser/extensions/api/media_galleries/media_galleries_api.cc index f5a40ff..e7e2927 100644 --- a/chrome/browser/extensions/api/media_galleries/media_galleries_api.cc +++ b/chrome/browser/extensions/api/media_galleries/media_galleries_api.cc @@ -79,7 +79,7 @@ bool MediaGalleriesGetMediaFileSystemsFunction::RunImpl() { } else if (interactive == "if_needed") { std::vector<MediaFileSystemRegistry::MediaFSInfo> filesystems = MediaFileSystemRegistry::GetInstance()->GetMediaFileSystemsForExtension( - render_view_host()->GetProcess(), *GetExtension()); + render_view_host(), GetExtension()); if (filesystems.empty()) ShowDialog(); else @@ -98,7 +98,7 @@ bool MediaGalleriesGetMediaFileSystemsFunction::RunImpl() { void MediaGalleriesGetMediaFileSystemsFunction::GetAndReturnGalleries() { std::vector<MediaFileSystemRegistry::MediaFSInfo> filesystems = MediaFileSystemRegistry::GetInstance()->GetMediaFileSystemsForExtension( - render_view_host()->GetProcess(), *GetExtension()); + render_view_host(), GetExtension()); ReturnGalleries(filesystems); } @@ -115,7 +115,7 @@ void MediaGalleriesGetMediaFileSystemsFunction::ReturnGalleries( "name", Value::CreateStringValue(filesystems[i].name)); list->Append(dict_value); - if (GetExtension()->HasAPIPermission( + if (!filesystems[i].path.empty() && GetExtension()->HasAPIPermission( extensions::APIPermission::kMediaGalleriesRead)) { content::ChildProcessSecurityPolicy* policy = ChildProcessSecurityPolicy::GetInstance(); diff --git a/chrome/browser/intents/device_attached_intent_source.cc b/chrome/browser/intents/device_attached_intent_source.cc index 60b9666..0f0244a 100644 --- a/chrome/browser/intents/device_attached_intent_source.cc +++ b/chrome/browser/intents/device_attached_intent_source.cc @@ -102,9 +102,7 @@ void DeviceAttachedIntentSource::OnRemovableStorageAttached( // Only handle mass storage for now. // TODO(kmadhusu): Handle all device types. http://crbug.com/140353. - MediaStorageUtil::Type type; - MediaStorageUtil::CrackDeviceId(id, &type, NULL); - if (type == MediaStorageUtil::MTP_OR_PTP) + if (!MediaStorageUtil::IsMassStorageDevice(id)) return; DCHECK(MediaStorageUtil::IsRemovableDevice(id)); diff --git a/chrome/browser/media_gallery/media_file_system_registry.cc b/chrome/browser/media_gallery/media_file_system_registry.cc index e2a32e1..9a39533 100644 --- a/chrome/browser/media_gallery/media_file_system_registry.cc +++ b/chrome/browser/media_gallery/media_file_system_registry.cc @@ -7,27 +7,35 @@ #include "chrome/browser/media_gallery/media_file_system_registry.h" #include <set> +#include <vector> +#include "base/callback.h" #include "base/file_path.h" #include "base/path_service.h" +#include "base/stl_util.h" #include "base/system_monitor/system_monitor.h" #include "base/utf_string_conversions.h" +#include "chrome/browser/media_gallery/media_galleries_preferences.h" +#include "chrome/browser/media_gallery/media_galleries_preferences_factory.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/system_monitor/media_storage_util.h" #include "chrome/common/chrome_paths.h" #include "chrome/common/extensions/extension_constants.h" #include "chrome/common/extensions/extension.h" #include "content/public/browser/browser_thread.h" +#include "content/public/browser/notification_observer.h" +#include "content/public/browser/notification_registrar.h" #include "content/public/browser/notification_source.h" #include "content/public/browser/notification_types.h" #include "content/public/browser/render_process_host.h" +#include "content/public/browser/render_view_host.h" +#include "content/public/browser/web_contents.h" #include "webkit/fileapi/file_system_types.h" #include "webkit/fileapi/isolated_context.h" #include "webkit/fileapi/media/media_file_system_config.h" #if defined(SUPPORT_MEDIA_FILESYSTEM) #include "webkit/fileapi/media/media_device_map_service.h" - -using fileapi::MediaDeviceMapService; #endif namespace chrome { @@ -37,23 +45,252 @@ static base::LazyInstance<MediaFileSystemRegistry>::Leaky using base::SystemMonitor; using content::BrowserThread; +using content::NavigationController; using content::RenderProcessHost; +using content::WebContents; using fileapi::IsolatedContext; namespace { -bool IsGalleryPermittedForExtension(const extensions::Extension& extension, - const FilePath::StringType& location) { - if (extension.HasAPIPermission( - extensions::APIPermission::kMediaGalleriesAllGalleries)) { - return true; +struct InvalidatedGalleriesInfo { + std::set<ExtensionGalleriesHost*> extension_hosts; + std::set<MediaGalleryPrefId> pref_ids; +}; + +std::string RegisterFileSystem(std::string device_id, const FilePath& path) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + + IsolatedContext* isolated_context = IsolatedContext::GetInstance(); + if (MediaStorageUtil::IsMassStorageDevice(device_id)) { + // Sanity checks for |path|. + CHECK(path.IsAbsolute()); + CHECK(!path.ReferencesParent()); + std::string fs_name(extension_misc::kMediaFileSystemPathPart); + const std::string fsid = isolated_context->RegisterFileSystemForPath( + fileapi::kFileSystemTypeNativeMedia, path, &fs_name); + CHECK(!fsid.empty()); + return fsid; } - // TODO(vandebo) Check with prefs for permission to this gallery. - return false; + + // TODO(kmadhusu) handle MTP devices. + NOTREACHED(); + return std::string(); } } // namespace +// Refcounted only so it can easily be put in map. All instances are owned +// by |MediaFileSystemRegistry::extension_hosts_map_|. +class ExtensionGalleriesHost + : public base::RefCounted<ExtensionGalleriesHost>, + public content::NotificationObserver { + public: + // |no_references_callback| is called when the last RenderViewHost reference + // goes away. RenderViewHost references are added through ReferenceFromRVH(). + explicit ExtensionGalleriesHost(const base::Closure& no_references_callback) + : no_references_callback_(no_references_callback) { + } + + // For each gallery in the list of permitted |galleries|, looks up or creates + // a file system id and returns the information needed for the renderer to + // create those file system objects. + std::vector<MediaFileSystemRegistry::MediaFSInfo> GetMediaFileSystems( + const MediaGalleryPrefIdSet& galleries, + const MediaGalleriesPrefInfoMap& galleries_info) { + std::vector<MediaFileSystemRegistry::MediaFSInfo> result; + for (std::set<MediaGalleryPrefId>::const_iterator id = galleries.begin(); + id != galleries.end(); + ++id) { + PrefIdFsInfoMap::const_iterator existing_info = pref_id_map_.find(*id); + if (existing_info != pref_id_map_.end()) { + result.push_back(existing_info->second); + continue; + } + const MediaGalleryPrefInfo& gallery_info = + galleries_info.find(*id)->second; + const std::string& device_id = gallery_info.device_id; + // TODO(kmadhusu) handle MTP devices. + DCHECK(MediaStorageUtil::IsMassStorageDevice(device_id)); + FilePath path = MediaStorageUtil::FindDevicePathById(device_id); + // TODO(vandebo) we also need to check that these galleries are attached. + // For now, just skip over entries that we couldn't find. + if (path.empty()) + continue; + CHECK(!path.empty()); + path = path.Append(gallery_info.path); + + MediaFileSystemRegistry::MediaFSInfo new_entry; + new_entry.name = gallery_info.display_name; + new_entry.path = path; + new_entry.fsid = RegisterFileSystem(device_id, path); + result.push_back(new_entry); + pref_id_map_[*id] = new_entry; + } + + // TODO(vandebo) We need a way of getting notification when permission for + // galleries are revoked (http://crbug.com/145855). For now, invalidate + // any fsid we have that we didn't get this time around. + if (galleries.size() != pref_id_map_.size()) { + MediaGalleryPrefIdSet old_galleries; + for (PrefIdFsInfoMap::const_iterator it = pref_id_map_.begin(); + it != pref_id_map_.end(); + ++it) { + old_galleries.insert(it->first); + } + MediaGalleryPrefIdSet invalid_galleries; + std::set_difference(old_galleries.begin(), old_galleries.end(), + galleries.begin(), galleries.end(), + std::inserter(invalid_galleries, + invalid_galleries.begin())); + for (MediaGalleryPrefIdSet::const_iterator it = invalid_galleries.begin(); + it != invalid_galleries.end(); + ++it) { + RevokeGalleryByPrefId(*it); + } + } + + return result; + } + + // TODO(kmadhusu): Clean up this code. http://crbug.com/140340. + // Revoke the file system for |id| if this extension has created one for |id|. + void RevokeGalleryByPrefId(MediaGalleryPrefId id) { + PrefIdFsInfoMap::iterator gallery = pref_id_map_.find(id); + if (gallery == pref_id_map_.end()) + return; + + IsolatedContext* isolated_context = IsolatedContext::GetInstance(); + isolated_context->RevokeFileSystem(gallery->second.fsid); + + pref_id_map_.erase(gallery); + } + + // Indicate that the passed |rvh| will reference the file system ids created + // by this class. It is safe to call this multiple times with the same RVH. + void ReferenceFromRVH(const content::RenderViewHost* rvh) { + WebContents* contents = WebContents::FromRenderViewHost(rvh); + if (registrar_.IsRegistered(this, + content::NOTIFICATION_WEB_CONTENTS_DESTROYED, + content::Source<WebContents>(contents))) { + return; + } + registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED, + content::Source<WebContents>(contents)); + registrar_.Add( + this, content::NOTIFICATION_NAV_ENTRY_COMMITTED, + content::Source<NavigationController>(&contents->GetController())); + + RenderProcessHost* rph = contents->GetRenderProcessHost(); + rph_refs_[rph].insert(contents); + if (rph_refs_[rph].size() == 1) { + registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED, + content::Source<RenderProcessHost>(rph)); + } + } + + // NotificationObserver implementation. + virtual void Observe(int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) OVERRIDE { + switch (type) { + case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: { + OnRendererProcessClosed( + content::Source<RenderProcessHost>(source).ptr()); + break; + } + case content::NOTIFICATION_WEB_CONTENTS_DESTROYED: { + OnWebContentsDestroyedOrNavigated( + content::Source<WebContents>(source).ptr()); + break; + } + case content::NOTIFICATION_NAV_ENTRY_COMMITTED: { + NavigationController* controller = + content::Source<NavigationController>(source).ptr(); + WebContents* contents = controller->GetWebContents(); + OnWebContentsDestroyedOrNavigated(contents); + break; + } + default: { + NOTREACHED(); + break; + } + } + } + + private: + typedef std::map<MediaGalleryPrefId, MediaFileSystemRegistry::MediaFSInfo> + PrefIdFsInfoMap; + typedef std::map<const RenderProcessHost*, std::set<const WebContents*> > + RenderProcessHostRefCount; + + // Private destructor and friend declaration for ref counted implementation. + friend class base::RefCounted<ExtensionGalleriesHost>; + + virtual ~ExtensionGalleriesHost() { + DCHECK(rph_refs_.empty()); + DCHECK(pref_id_map_.empty()); + } + + void OnRendererProcessClosed(const RenderProcessHost* rph) { + RenderProcessHostRefCount::const_iterator rph_info = rph_refs_.find(rph); + DCHECK(rph_info != rph_refs_.end()); + // We're going to remove everything from the set, so we make a copy + // before operating on it. + std::set<const WebContents*> closed_web_contents = rph_info->second; + DCHECK(!closed_web_contents.empty()); + + for (std::set<const WebContents*>::const_iterator it = + closed_web_contents.begin(); + it != closed_web_contents.end(); + ++it) { + OnWebContentsDestroyedOrNavigated(*it); + } + } + + void OnWebContentsDestroyedOrNavigated(const WebContents* contents) { + registrar_.Remove(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED, + content::Source<WebContents>(contents)); + registrar_.Remove( + this, content::NOTIFICATION_NAV_ENTRY_COMMITTED, + content::Source<NavigationController>(&contents->GetController())); + + RenderProcessHost* rph = contents->GetRenderProcessHost(); + RenderProcessHostRefCount::iterator process_refs = rph_refs_.find(rph); + DCHECK(process_refs != rph_refs_.end()); + process_refs->second.erase(contents); + if (process_refs->second.empty()) { + registrar_.Remove(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED, + content::Source<RenderProcessHost>(rph)); + rph_refs_.erase(process_refs); + } + + if (rph_refs_.empty()) { + IsolatedContext* isolated_context = IsolatedContext::GetInstance(); + for (PrefIdFsInfoMap::const_iterator it = pref_id_map_.begin(); + it != pref_id_map_.end(); + ++it) { + isolated_context->RevokeFileSystem(it->second.fsid); + } + pref_id_map_.clear(); + no_references_callback_.Run(); + } + } + + // A callback to call when the last RVH reference goes away. + base::Closure no_references_callback_; + + // A map from the gallery preferences id to the file system information. + PrefIdFsInfoMap pref_id_map_; + + // The set of render processes and web contents that may have references to + // the file system ids this instance manages. + RenderProcessHostRefCount rph_refs_; + + // A registrar for listening notifications. + content::NotificationRegistrar registrar_; + + DISALLOW_COPY_AND_ASSIGN(ExtensionGalleriesHost); +}; /****************** * Public methods @@ -64,88 +301,88 @@ MediaFileSystemRegistry* MediaFileSystemRegistry::GetInstance() { return g_media_file_system_registry.Pointer(); } +// TODO(vandebo) We need to make this async so that we check that the +// galleries are attached (requires the file thread). std::vector<MediaFileSystemRegistry::MediaFSInfo> MediaFileSystemRegistry::GetMediaFileSystemsForExtension( - const content::RenderProcessHost* rph, - const extensions::Extension& extension) { + const content::RenderViewHost* rvh, + const extensions::Extension* extension) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - std::vector<MediaFSInfo> results; - std::pair<ChildIdToMediaFSMap::iterator, bool> ret = - media_fs_map_.insert(std::make_pair(rph, MediaPathToFSIDMap())); - ChildIdToMediaFSMap::iterator& child_it = ret.first; - if (ret.second) { - // Never seen a GetMediaFileSystems call from this RPH. Initialize its - // file system mappings. - RegisterForRPHGoneNotifications(rph); - FilePath pictures_path; - // TODO(vandebo) file system galleries need a unique id as well. - if (PathService::Get(chrome::DIR_USER_PICTURES, &pictures_path) && - IsGalleryPermittedForExtension(extension, pictures_path.value())) { - std::string fsid = RegisterPathAsFileSystem(pictures_path); - child_it->second.insert(std::make_pair(pictures_path, fsid)); - } - } - - // TODO(thestig) Handle overlap between devices and media directories. - SystemMonitor* monitor = SystemMonitor::Get(); - const std::vector<SystemMonitor::RemovableStorageInfo> media_devices = - monitor->GetAttachedRemovableStorage(); - for (size_t i = 0; i < media_devices.size(); ++i) { - MediaStorageUtil::Type type; - MediaStorageUtil::CrackDeviceId(media_devices[i].device_id, &type, NULL); - // TODO(vandebo) Handle MTP devices. - if (type != MediaStorageUtil::MTP_OR_PTP && - IsGalleryPermittedForExtension(extension, media_devices[i].location)) { - device_id_map_.insert(std::make_pair(media_devices[i].device_id, - media_devices[i])); - FilePath path(media_devices[i].location); - const std::string fsid = RegisterPathAsFileSystem(path); - child_it->second.insert(std::make_pair(path, fsid)); - } + Profile* profile = + Profile::FromBrowserContext(rvh->GetProcess()->GetBrowserContext()); + MediaGalleriesPreferences* preferences = + MediaGalleriesPreferencesFactory::GetForProfile(profile); + MediaGalleryPrefIdSet galleries = + preferences->GalleriesForExtension(*extension); + ExtensionGalleriesHost* extension_host = + extension_hosts_map_[profile][extension->id()].get(); + + // If the extension has no galleries and it didn't have any last time, just + // return the empty list. The second check is needed because of + // http://crbug.com/145855. + if (galleries.empty() && !extension_host) + return std::vector<MediaFileSystemRegistry::MediaFSInfo>(); + + if (!extension_host) { + extension_host = new ExtensionGalleriesHost( + base::Bind(&MediaFileSystemRegistry::OnExtensionGalleriesHostEmpty, + base::Unretained(this), profile, extension->id())); + extension_hosts_map_[profile][extension->id()] = extension_host; } + extension_host->ReferenceFromRVH(rvh); - MediaPathToFSIDMap& child_map = child_it->second; - for (MediaPathToFSIDMap::const_iterator it = child_map.begin(); - it != child_map.end(); - ++it) { - MediaFSInfo entry; - // TODO(vandebo) use a better name, fsid for now. - entry.name = it->second; - entry.fsid = it->second; - entry.path = it->first; - results.push_back(entry); - } - return results; + return extension_host->GetMediaFileSystems(galleries, + preferences->known_galleries()); } +// TODO(vandebo) We also need to listen for the attach event and add newly +// attached media devices to MediaGalleriesPreferences. void MediaFileSystemRegistry::OnRemovableStorageDetached( const std::string& id) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - DeviceIdToInfoMap::iterator it = device_id_map_.find(id); - if (it == device_id_map_.end()) - return; + // Since revoking a gallery in the ExtensionGalleriesHost may cause it + // to be removed from the map and therefore invalidate any iterator pointing + // to it, this code first copies all the invalid gallery ids and the + // extension hosts in which they may appear (per profile) and revoked it in + // a second step. + std::vector<InvalidatedGalleriesInfo> invalid_galleries_info; + + for (ExtensionGalleriesHostMap::iterator profile_it = + extension_hosts_map_.begin(); + profile_it != extension_hosts_map_.end(); + ++profile_it) { + MediaGalleriesPreferences* preferences = + MediaGalleriesPreferencesFactory::GetForProfile(profile_it->first); + InvalidatedGalleriesInfo invalid_galleries_in_profile; + invalid_galleries_in_profile.pref_ids = + preferences->LookUpGalleriesByDeviceId(id); + + for (ExtensionHostMap::const_iterator extension_host_it = + profile_it->second.begin(); + extension_host_it != profile_it->second.end(); + ++extension_host_it) { + invalid_galleries_in_profile.extension_hosts.insert( + extension_host_it->second.get()); + } - FilePath path(it->second.location); - RevokeMediaFileSystem(path); - device_id_map_.erase(it); -} + invalid_galleries_info.push_back(invalid_galleries_in_profile); + } -void MediaFileSystemRegistry::Observe( - int type, - const content::NotificationSource& source, - const content::NotificationDetails& details) { - DCHECK(type == content::NOTIFICATION_RENDERER_PROCESS_CLOSED || - type == content::NOTIFICATION_RENDERER_PROCESS_TERMINATED); - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - const RenderProcessHost* rph = - content::Source<content::RenderProcessHost>(source).ptr(); - ChildIdToMediaFSMap::iterator child_it = media_fs_map_.find(rph); - CHECK(child_it != media_fs_map_.end()); - // No need to revoke the isolated file systems. The RPH will do that. - media_fs_map_.erase(child_it); - UnregisterForRPHGoneNotifications(rph); + for (size_t i = 0; i < invalid_galleries_info.size(); i++) { + for (std::set<ExtensionGalleriesHost*>::const_iterator extension_host_it = + invalid_galleries_info[i].extension_hosts.begin(); + extension_host_it != invalid_galleries_info[i].extension_hosts.end(); + ++extension_host_it) { + for (std::set<MediaGalleryPrefId>::const_iterator pref_id_it = + invalid_galleries_info[i].pref_ids.begin(); + pref_id_it != invalid_galleries_info[i].pref_ids.end(); + ++pref_id_it) { + (*extension_host_it)->RevokeGalleryByPrefId(*pref_id_it); + } + } + } } /****************** @@ -157,6 +394,8 @@ MediaFileSystemRegistry::MediaFileSystemRegistry() { SystemMonitor* system_monitor = SystemMonitor::Get(); if (system_monitor) system_monitor->AddDevicesChangedObserver(this); + // TODO(vandebo) We should add all the currently attached media devices + // to MediaGalleriesPreferences here. } MediaFileSystemRegistry::~MediaFileSystemRegistry() { @@ -166,56 +405,18 @@ MediaFileSystemRegistry::~MediaFileSystemRegistry() { system_monitor->RemoveDevicesChangedObserver(this); } -void MediaFileSystemRegistry::RegisterForRPHGoneNotifications( - const content::RenderProcessHost* rph) { - registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED, - content::Source<RenderProcessHost>(rph)); - registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED, - content::Source<RenderProcessHost>(rph)); -} - -void MediaFileSystemRegistry::UnregisterForRPHGoneNotifications( - const content::RenderProcessHost* rph) { - registrar_.Remove(this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED, - content::Source<RenderProcessHost>(rph)); - registrar_.Remove(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED, - content::Source<RenderProcessHost>(rph)); -} - -std::string MediaFileSystemRegistry::RegisterPathAsFileSystem( - const FilePath& path) { +void MediaFileSystemRegistry::OnExtensionGalleriesHostEmpty( + Profile* profile, const std::string& extension_id) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - // Sanity checks for |path|. - CHECK(path.IsAbsolute()); - CHECK(!path.ReferencesParent()); - - // The directory name is not exposed to the js layer and we simply use - // a fixed name (as we only register a single directory per file system). - std::string register_name(extension_misc::kMediaFileSystemPathPart); - const std::string fsid = - IsolatedContext::GetInstance()->RegisterFileSystemForPath( - fileapi::kFileSystemTypeNativeMedia, path, ®ister_name); - CHECK(!fsid.empty()); - return fsid; -} - -void MediaFileSystemRegistry::RevokeMediaFileSystem(const FilePath& path) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - - IsolatedContext* isolated_context = IsolatedContext::GetInstance(); - isolated_context->RevokeFileSystemByPath(path); - - for (ChildIdToMediaFSMap::iterator child_it = media_fs_map_.begin(); - child_it != media_fs_map_.end(); - ++child_it) { - MediaPathToFSIDMap& child_map = child_it->second; - MediaPathToFSIDMap::iterator media_path_it = child_map.find(path); - if (media_path_it == child_map.end()) - continue; - - child_map.erase(media_path_it); - } + ExtensionGalleriesHostMap::iterator extension_hosts = + extension_hosts_map_.find(profile); + DCHECK(extension_hosts != extension_hosts_map_.end()); + ExtensionHostMap::size_type erase_count = + extension_hosts->second.erase(extension_id); + DCHECK_EQ(1U, erase_count); + if (extension_hosts->second.empty()) + extension_hosts_map_.erase(extension_hosts); } } // namespace chrome diff --git a/chrome/browser/media_gallery/media_file_system_registry.h b/chrome/browser/media_gallery/media_file_system_registry.h index f5267976..e6bf64a 100644 --- a/chrome/browser/media_gallery/media_file_system_registry.h +++ b/chrome/browser/media_gallery/media_file_system_registry.h @@ -15,14 +15,14 @@ #include "base/basictypes.h" #include "base/lazy_instance.h" +#include "base/file_path.h" +#include "base/memory/ref_counted.h" #include "base/system_monitor/system_monitor.h" -#include "content/public/browser/notification_observer.h" -#include "content/public/browser/notification_registrar.h" -class FilePath; +class Profile; namespace content { -class RenderProcessHost; +class RenderViewHost; } namespace extensions { @@ -35,12 +35,13 @@ class IsolatedContext; namespace chrome { +class ExtensionGalleriesHost; + class MediaFileSystemRegistry - : public base::SystemMonitor::DevicesChangedObserver, - public content::NotificationObserver { + : public base::SystemMonitor::DevicesChangedObserver { public: struct MediaFSInfo { - std::string name; + string16 name; std::string fsid; FilePath path; }; @@ -48,57 +49,34 @@ class MediaFileSystemRegistry // The instance is lazily created per browser process. static MediaFileSystemRegistry* GetInstance(); - // Returns the list of media filesystem IDs and paths for a given RPH. + // Returns the list of media filesystem IDs and paths for a given RVH. // Called on the UI thread. std::vector<MediaFSInfo> GetMediaFileSystemsForExtension( - const content::RenderProcessHost* rph, - const extensions::Extension& extension); + const content::RenderViewHost* rvh, + const extensions::Extension* extension); // base::SystemMonitor::DevicesChangedObserver implementation. virtual void OnRemovableStorageDetached(const std::string& id) OVERRIDE; - // content::NotificationObserver implementation. - virtual void Observe(int type, - const content::NotificationSource& source, - const content::NotificationDetails& details) OVERRIDE; - private: friend struct base::DefaultLazyInstanceTraits<MediaFileSystemRegistry>; - // Mapping of media directories to filesystem IDs. - typedef std::map<FilePath, std::string> MediaPathToFSIDMap; - - // Mapping of RPH to MediaPathToFSIDMaps. - typedef std::map<const content::RenderProcessHost*, - MediaPathToFSIDMap> ChildIdToMediaFSMap; - - // Mapping of device id to media device info. - typedef std::map<std::string, base::SystemMonitor::RemovableStorageInfo> - DeviceIdToInfoMap; + // Map an extension to the ExtensionGalleriesHost. + typedef std::map<std::string /*extension_id*/, + scoped_refptr<ExtensionGalleriesHost> > ExtensionHostMap; + // Map a profile and extension to the ExtensionGalleriesHost. + typedef std::map<Profile*, ExtensionHostMap> ExtensionGalleriesHostMap; // Obtain an instance of this class via GetInstance(). MediaFileSystemRegistry(); virtual ~MediaFileSystemRegistry(); - // Helper functions to register / unregister listening for renderer process - // closed / terminiated notifications. - void RegisterForRPHGoneNotifications(const content::RenderProcessHost* rph); - void UnregisterForRPHGoneNotifications(const content::RenderProcessHost* rph); - - // Registers a path as a media file system and return the filesystem id. - std::string RegisterPathAsFileSystem(const FilePath& path); - - // Revoke a media file system with a given |path|. - void RevokeMediaFileSystem(const FilePath& path); - - // Only accessed on the UI thread. - ChildIdToMediaFSMap media_fs_map_; - - // Only accessed on the UI thread. - DeviceIdToInfoMap device_id_map_; + void OnExtensionGalleriesHostEmpty(Profile* profile, + const std::string& extension_id); - // Is only used on the UI thread. - content::NotificationRegistrar registrar_; + // Only accessed on the UI thread. This map owns all the + // ExtensionGalleriesHost objects created. + ExtensionGalleriesHostMap extension_hosts_map_; DISALLOW_COPY_AND_ASSIGN(MediaFileSystemRegistry); }; diff --git a/chrome/browser/system_monitor/media_storage_util.cc b/chrome/browser/system_monitor/media_storage_util.cc index a5dce62..8a0d057 100644 --- a/chrome/browser/system_monitor/media_storage_util.cc +++ b/chrome/browser/system_monitor/media_storage_util.cc @@ -33,19 +33,11 @@ static void (*g_test_get_device_info_from_path_function)( const FilePath& path, std::string* device_id, string16* device_name, FilePath* relative_path) = NULL; -void EmptyPathIsFalseCallback(const MediaStorageUtil::BoolCallback& callback, - FilePath path) { - callback.Run(!path.empty()); -} - void ValidatePathOnFileThread( - const FilePath& path, const MediaStorageUtil::FilePathCallback& callback) { + const FilePath& path, const MediaStorageUtil::BoolCallback& callback) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); - FilePath result; - if (file_util::PathExists(path)) - result = path; BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, - base::Bind(callback, path)); + base::Bind(callback, file_util::PathExists(path))); } FilePath::StringType FindRemovableStorageLocationById( @@ -123,6 +115,12 @@ bool MediaStorageUtil::IsRemovableDevice(const std::string& device_id) { } // static +bool MediaStorageUtil::IsMassStorageDevice(const std::string& device_id) { + Type type; + return CrackDeviceId(device_id, &type, NULL) && type != MTP_OR_PTP; +} + +// static void MediaStorageUtil::IsDeviceAttached(const std::string& device_id, const BoolCallback& callback) { Type type; @@ -141,11 +139,10 @@ void MediaStorageUtil::IsDeviceAttached(const std::string& device_id, break; case FIXED_MASS_STORAGE: // For this type, the unique_id is the path. - BrowserThread::PostTask( - BrowserThread::FILE, FROM_HERE, - base::Bind(&ValidatePathOnFileThread, - FilePath::FromUTF8Unsafe(unique_id), - base::Bind(&EmptyPathIsFalseCallback, callback))); + BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, + base::Bind(&ValidatePathOnFileThread, + FilePath::FromUTF8Unsafe(unique_id), + callback)); break; } NOTREACHED(); @@ -166,32 +163,26 @@ void MediaStorageUtil::GetDeviceInfoFromPath(const FilePath& path, } // static -void MediaStorageUtil::FindDevicePathById(const std::string& device_id, - const FilePathCallback& callback) { +FilePath MediaStorageUtil::FindDevicePathById(const std::string& device_id) { Type type; std::string unique_id; if (!CrackDeviceId(device_id, &type, &unique_id)) - callback.Run(FilePath()); + return FilePath(); switch (type) { case MTP_OR_PTP: // TODO(kmadhusu) We may want to return the MTP device location here. - callback.Run(FilePath()); - break; + return FilePath(); case REMOVABLE_MASS_STORAGE_WITH_DCIM: // Fall through. case REMOVABLE_MASS_STORAGE_NO_DCIM: - callback.Run(FilePath(FindRemovableStorageLocationById(device_id))); - break; + return FilePath(FindRemovableStorageLocationById(device_id)); case FIXED_MASS_STORAGE: // For this type, the unique_id is the path. - BrowserThread::PostTask( - BrowserThread::FILE, FROM_HERE, - base::Bind(&ValidatePathOnFileThread, - FilePath::FromUTF8Unsafe(unique_id), callback)); - break; + return FilePath::FromUTF8Unsafe(unique_id); } + NOTREACHED(); - callback.Run(FilePath()); + return FilePath(); } // static diff --git a/chrome/browser/system_monitor/media_storage_util.h b/chrome/browser/system_monitor/media_storage_util.h index 827b8ce..bccaec5 100644 --- a/chrome/browser/system_monitor/media_storage_util.h +++ b/chrome/browser/system_monitor/media_storage_util.h @@ -30,7 +30,6 @@ class MediaStorageUtil { }; typedef base::Callback<void(bool)> BoolCallback; - typedef base::Callback<void(FilePath)> FilePathCallback; // Returns a device id given properties of the device. A prefix dependent on // |type| is added so |unique_id| need only be unique within the given type. @@ -50,6 +49,10 @@ class MediaStorageUtil { // (type isn't FIXED_MASS_STORAGE). static bool IsRemovableDevice(const std::string& device_id); + // Looks inside |device_id| to determine if it is a mass storage device + // (type isn't MTP_OR_PTP). + static bool IsMassStorageDevice(const std::string& device_id); + // Determines if the device is attached to the computer. static void IsDeviceAttached(const std::string& device_id, const BoolCallback& callback); @@ -61,10 +64,10 @@ class MediaStorageUtil { string16* device_name, FilePath* relative_path); - // Get a FilePath for the given |device_id|. If the device isn't connected - // or isn't a mass storage type, the FilePath will be empty. - static void FindDevicePathById(const std::string& device_id, - const FilePathCallback& callback); + // Get a FilePath for the given |device_id|. If the device isn't a mass + // storage type, the FilePath will be empty. This does not check that + // the device is connected. + static FilePath FindDevicePathById(const std::string& device_id); protected: typedef void (*GetDeviceInfoFromPathFunction)(const FilePath& path, |