| Index: chrome/browser/media_gallery/media_file_system_registry.cc
|
| diff --git a/chrome/browser/media_gallery/media_file_system_registry.cc b/chrome/browser/media_gallery/media_file_system_registry.cc
|
| index 8ea90f30cf14b4a14bcc86815b42f03f63a52d32..2557accdbb606d644c74c6643acdd2c35976b77a 100644
|
| --- a/chrome/browser/media_gallery/media_file_system_registry.cc
|
| +++ b/chrome/browser/media_gallery/media_file_system_registry.cc
|
| @@ -26,8 +26,6 @@
|
|
|
| #if defined(SUPPORT_MEDIA_FILESYSTEM)
|
| #include "webkit/fileapi/media/media_device_map_service.h"
|
| -
|
| -using fileapi::MediaDeviceMapService;
|
| #endif
|
|
|
| namespace chrome {
|
| @@ -42,16 +40,208 @@ using fileapi::IsolatedContext;
|
|
|
| namespace {
|
|
|
| -bool IsGalleryPermittedForExtension(const extensions::Extension& extension,
|
| - const FilePath::StringType& location) {
|
| - if (extension.HasAPIPermission(
|
| - extensions::APIPermission::kMediaGalleriesAllGalleries)) {
|
| - return true;
|
| +FilePath DeviceIdToPath(std::string device_id) {
|
| + // TODO(vandebo) This needs to be cleaned up. We need a device manager
|
| + // type class that will handle this kind of thing. Right now
|
| + // MediaFileSystemRegistry::GetDeviceIdFromPath just turns the path into
|
| + // a string, so for now we can just go the other way.
|
| + return FilePath(device_id);
|
| +}
|
| +
|
| +std::string MediaFileSystemRegistry::RegisterPathAsFileSystem(
|
| + const SystemMonitor::MediaDeviceType& device_type,
|
| + std::string device_id,
|
| + const FilePath& relative_path) {
|
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| +
|
| +
|
| + IsolatedContext* isolated_context = IsolatedContext::GetInstance();
|
| + if (device_type == SystemMonitor::TYPE_PATH) {
|
| + FilePath path = DeviceIdToPath(device_id).Append(relative_path);
|
| + // Sanity checks for |path|.
|
| + CHECK(path.IsAbsolute());
|
| + CHECK(!path.ReferencesParent());
|
| + const std::string fsid = isolated_context->RegisterFileSystemForPath(
|
| + fileapi::kFileSystemTypeNativeMedia,
|
| + path,
|
| + extension_misc::kMediaFileSystemPathPart);
|
| + CHECK(!fsid.empty());
|
| + return fsid;
|
| }
|
| - // TODO(vandebo) Check with prefs for permission to this gallery.
|
| - return false;
|
| +
|
| + // TODO(vandebo) handle device_type == case SystemMonitor::TYPE_MTP.
|
| + NOTREACHED();
|
| + return std::string();
|
| }
|
|
|
| +class ExtensionGalleriesHost : public content::NotificationObserver {
|
| + public:
|
| + typedef base::Callback<void(void)> NoReferenecesCallback;
|
| +
|
| + explicit ExtensionGalleriesHost(const NoReferencesCallback& callback)
|
| + : callback_(callback) {
|
| + }
|
| + virtual ~ExtensionGalleriesHost() {
|
| + DCHECK(rph_refs_.empty());
|
| + DCHECK(pref_id_map_.empty());
|
| + }
|
| +
|
| + // Lookup the galleries for this extension, turn those into file system ids
|
| + // and return the information needed for the renderer to create those file
|
| + // system objects.
|
| + std::vector<MediaFSInfo> GetMediaFileSystems(
|
| + const MediaGalleryPrefIdSet& galleries,
|
| + const MediaGalleriesPrefInfoMap& galleries_info) {
|
| + std::vector<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.append(*existing_info);
|
| + continue;
|
| + }
|
| + // TODO(vandebo): For MTP, path is empty.
|
| + MediaFsInfo new_entry;
|
| + new_entry.name = galleries_info[*id].display_name;
|
| + new_entry.path = FilePath path = DeviceIdToPath(
|
| + galleries_info[*id].device_id).Append(galleries_info[*id].path);
|
| + // TODO(vandebo): Get type out of galleries_info.
|
| + new_entry.fsid = RegisterPathAsFileSystem(SystemMonitor::TYPE_PATH,
|
| + galleries_info[*id].device_id,
|
| + galleries_info[*id].path);
|
| + result.append(new_entry);
|
| + pref_id_map_[pref_id] = new_entry;
|
| + }
|
| + return result;
|
| + }
|
| +
|
| + // If this extension has created a file system id for the given gallery
|
| + // then revoke it.
|
| + 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->fsid);
|
| +
|
| + pref_id_map_.erase(gallery);
|
| + }
|
| +
|
| + // Indicate that the passed render process 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()));
|
| +
|
| + content::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<content::RenderProcessHost>(rph));
|
| + }
|
| + }
|
| +
|
| + // NotificationObserver implementation.
|
| + virtual void Observe(int type,
|
| + const NotificationSource& source,
|
| + const NotificationDetails& details) {
|
| + switch (type) {
|
| + case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: {
|
| + OnRendererProcessClosed(
|
| + content::Source<content::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<MediaGalleriesPrefId, MediaFSInfo> PrefIdFsInfoMap;
|
| + typedef std::map<const content::RenderProcessHost*,
|
| + std::set<const WebContent*> > RenderProcessHostRefCount;
|
| +
|
| + void OnRendererProcessClosed(const contents::RenderProcessHost* rph) {
|
| + std::set<const Content*> dead_rvhs = rph_refs_[rph];
|
| + DCHECK(!dead_rvhs.empty());
|
| +
|
| + for (std::set<const Content*>::const_iterator it = dead_rvhs.begin();
|
| + it != dead_rvhs.end();
|
| + ++it) {
|
| + OnWebContentsDestroyedOrNavigated(*it);
|
| + }
|
| + DCHECK(rph_refs_.find(rph) == rph_refs_.end());
|
| + }
|
| +
|
| + 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()));
|
| +
|
| + content::RenderProcessHost* rph = contents->GetRenderProcessHost();
|
| + rph_refs_[rph].erase(contents);
|
| + if (rph_refs_[rph].empty()) {
|
| + registrar_.Remove(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
|
| + content::Source<content::RenderProcessHost>(rph));
|
| + rph_refs_.erase(rph);
|
| + }
|
| +
|
| + 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->fsid);
|
| + }
|
| + pref_id_map_.clear();
|
| + callback_.Run();
|
| + }
|
| + }
|
| +
|
| + // A callback to call when the last RVH reference goes away.
|
| + const NoReferencesCallback& callback_;
|
| +
|
| + // A map from the gallery preferences id to the file system id.
|
| + 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);
|
| +};
|
| +
|
| } // namespace
|
|
|
|
|
| @@ -66,85 +256,85 @@ MediaFileSystemRegistry* MediaFileSystemRegistry::GetInstance() {
|
|
|
| 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::MediaDeviceInfo> media_devices =
|
| - monitor->GetAttachedMediaDevices();
|
| - for (size_t i = 0; i < media_devices.size(); ++i) {
|
| - MediaStorageUtil::Type type;
|
| - MediaStorageUtil::CrackDeviceId(media_devices[i].unique_id, &type, NULL);
|
| - // TODO(vandebo) Handle MTP devices.
|
| - if (type != MediaStorageUtil::USB_MTP &&
|
| - IsGalleryPermittedForExtension(extension, media_devices[i].location)) {
|
| - device_id_map_.insert(std::make_pair(media_devices[i].unique_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);
|
| + if (galleries.empty())
|
| + return std::vector<MediaFileSystemRegistry::MediaFSInfo>();
|
| +
|
| + ExtensionGalleriesHost* extension_host =
|
| + extension_host_map[profile][extension].get();
|
| + if (!extension_host) {
|
| + extension_host_map_[profile][extension].reset(new ExtensionGalleriesHost(
|
| + *extension,
|
| + base::Bind(&MediaFileSystemRegistry::OnExtensionGalleriesHostEmpty,
|
| + base::Unretained(this), profile, extension)));
|
| + extension_host = extension_host_map[profile][extension].get();
|
| }
|
| + 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());
|
| }
|
|
|
| void MediaFileSystemRegistry::OnMediaDeviceDetached(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, we first make a list of all the ExtensionGalleriesHost*, pref_id
|
| + // pairs to invalidate and then invalidate them in a second step.
|
| + struct InvalidatedGallery {
|
| + ExtensionGalleriesHost* extension_host;
|
| + MediaGalleriesPrefId pref_id;
|
| + };
|
| + std::vector<InvalidatedGallery> invalidated_galleries;
|
| +
|
| + for (ExtensionGalleriesHostMap::const_iterator extension_host_map =
|
| + extension_host_map_.begin();
|
| + extension_host_map != extension_host_map_.end();
|
| + ++extension_host_map) {
|
| + MediaGalleriesPreferences* preferences =
|
| + MediaGalleriesPreferencesFactory::GetForProfile(
|
| + extension_host_map.first);
|
| + MediaGalleryPrefIdSet detached_galleries =
|
| + preferences->LookUpGalleriesByDeviceId(id);
|
| + for (ExtensionHostMap::const_iterator extension_host =
|
| + extension_host_map.second.begin();
|
| + extension_host_map.second.end();
|
| + ++extension_host) {
|
| + for (MediaGalleryPrefIdSet::const_iterator pref_id =
|
| + detached_galleries.begin();
|
| + pref_id != detached_galleries.end();
|
| + ++pref_id) {
|
| + InvalidatedGallery gallery;
|
| + gallery.extension_host = extesion_host.second.get();
|
| + gallery.pref_id = *pref_id;
|
| + invalidated_galleries.push_back(gallery);
|
| + }
|
| + }
|
| + }
|
|
|
| - FilePath path(it->second.location);
|
| - RevokeMediaFileSystem(path);
|
| - device_id_map_.erase(it);
|
| -}
|
| + for (std::vector<InvalidatedGallery>::const_iterator it =
|
| + invalidated_galleries.begin();
|
| + it != invalidated_galleries.end();
|
| + ++it) {
|
| + it->extension_host->RevokeGalleryByPrefId(it->pref_id);
|
| + }
|
|
|
| -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);
|
| + // TODO(kmadhusu, vandebo): Clean up this code. http://crbug.com/140340.
|
| + // FIXME - from the device id, we need the device location.
|
| +#if defined(SUPPORT_MEDIA_FILESYSTEM)
|
| + //fileapi::MediaDeviceMapService::GetInstance()->RemoveMediaDevice(
|
| + // device_location);
|
| +#endif
|
| }
|
|
|
| std::string MediaFileSystemRegistry::GetDeviceIdFromPath(
|
| @@ -172,56 +362,15 @@ 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) {
|
| - 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);
|
| - }
|
| +void MediaFileSystemRegistry::OnExtensionGalleriesHostEmpty(
|
| + const Profile* profile,
|
| + const extensions::Extension* extension) {
|
| + ExtensionHostMap extension_hosts = extension_host_map_[profile];
|
| + DCHECK(!extension_hosts.empty());
|
| + ExtensionHostMap::size_type erase_count = extension_hosts.erase(extension);
|
| + DCHECK_EQ(1, erase_count);
|
| + if (extension_hosts.empty())
|
| + extension_host_map_.erase(profile);
|
| }
|
|
|
| } // namespace chrome
|
|
|