Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(5737)

Unified Diff: chrome/browser/media_gallery/media_file_system_registry.cc

Issue 10871049: Connect MediaFileSystemRegistry with MediaGalleriesPreferences (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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, &register_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

Powered by Google App Engine
This is Rietveld 408576698