Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 // MediaFileSystemRegistry implementation. | 5 // MediaFileSystemRegistry implementation. |
| 6 | 6 |
| 7 #include "chrome/browser/media_gallery/media_file_system_registry.h" | 7 #include "chrome/browser/media_gallery/media_file_system_registry.h" |
| 8 | 8 |
| 9 #include <set> | 9 #include <set> |
| 10 | 10 |
| 11 #include "base/callback.h" | |
| 11 #include "base/file_path.h" | 12 #include "base/file_path.h" |
| 12 #include "base/path_service.h" | 13 #include "base/path_service.h" |
| 13 #include "base/system_monitor/system_monitor.h" | 14 #include "base/system_monitor/system_monitor.h" |
| 14 #include "base/utf_string_conversions.h" | 15 #include "base/utf_string_conversions.h" |
| 16 #include "chrome/browser/media_gallery/media_galleries_preferences.h" | |
| 17 #include "chrome/browser/media_gallery/media_galleries_preferences_factory.h" | |
| 15 #include "chrome/browser/media_gallery/media_storage_util.h" | 18 #include "chrome/browser/media_gallery/media_storage_util.h" |
| 19 #include "chrome/browser/profiles/profile.h" | |
| 16 #include "chrome/common/chrome_paths.h" | 20 #include "chrome/common/chrome_paths.h" |
| 17 #include "chrome/common/extensions/extension_constants.h" | 21 #include "chrome/common/extensions/extension_constants.h" |
| 18 #include "chrome/common/extensions/extension.h" | 22 #include "chrome/common/extensions/extension.h" |
| 19 #include "content/public/browser/browser_thread.h" | 23 #include "content/public/browser/browser_thread.h" |
| 24 #include "content/public/browser/notification_observer.h" | |
| 25 #include "content/public/browser/notification_registrar.h" | |
| 20 #include "content/public/browser/notification_source.h" | 26 #include "content/public/browser/notification_source.h" |
| 21 #include "content/public/browser/notification_types.h" | 27 #include "content/public/browser/notification_types.h" |
| 22 #include "content/public/browser/render_process_host.h" | 28 #include "content/public/browser/render_process_host.h" |
| 29 #include "content/public/browser/render_view_host.h" | |
| 30 #include "content/public/browser/web_contents.h" | |
| 23 #include "webkit/fileapi/file_system_types.h" | 31 #include "webkit/fileapi/file_system_types.h" |
| 24 #include "webkit/fileapi/isolated_context.h" | 32 #include "webkit/fileapi/isolated_context.h" |
| 25 #include "webkit/fileapi/media/media_file_system_config.h" | 33 #include "webkit/fileapi/media/media_file_system_config.h" |
| 26 | 34 |
| 27 #if defined(SUPPORT_MEDIA_FILESYSTEM) | 35 #if defined(SUPPORT_MEDIA_FILESYSTEM) |
| 28 #include "webkit/fileapi/media/media_device_map_service.h" | 36 #include "webkit/fileapi/media/media_device_map_service.h" |
| 29 | |
| 30 using fileapi::MediaDeviceMapService; | |
| 31 #endif | 37 #endif |
| 32 | 38 |
| 33 namespace chrome { | 39 namespace chrome { |
| 34 | 40 |
| 35 static base::LazyInstance<MediaFileSystemRegistry>::Leaky | 41 static base::LazyInstance<MediaFileSystemRegistry>::Leaky |
| 36 g_media_file_system_registry = LAZY_INSTANCE_INITIALIZER; | 42 g_media_file_system_registry = LAZY_INSTANCE_INITIALIZER; |
| 37 | 43 |
| 38 using base::SystemMonitor; | 44 using base::SystemMonitor; |
| 39 using content::BrowserThread; | 45 using content::BrowserThread; |
| 46 using content::NavigationController; | |
| 40 using content::RenderProcessHost; | 47 using content::RenderProcessHost; |
| 48 using content::WebContents; | |
| 41 using fileapi::IsolatedContext; | 49 using fileapi::IsolatedContext; |
| 42 | 50 |
| 43 namespace { | 51 namespace { |
| 44 | 52 |
| 45 bool IsGalleryPermittedForExtension(const extensions::Extension& extension, | 53 struct InvalidatedGallery { |
|
Lei Zhang
2012/09/04 23:38:51
Move this to inside MediaFileSystemRegistry::OnRem
vandebo (ex-Chrome)
2012/09/05 00:58:12
I did try that originally, but the compiler compla
| |
| 46 const FilePath::StringType& location) { | 54 ExtensionGalleriesHost* extension_host; |
| 47 if (extension.HasAPIPermission( | 55 MediaGalleryPrefId pref_id; |
| 48 extensions::APIPermission::kMediaGalleriesAllGalleries)) { | 56 }; |
| 49 return true; | 57 |
| 50 } | 58 typedef std::list<InvalidatedGallery> InvalidatedGalleries; |
|
Lei Zhang
2012/09/04 23:38:51
nit: #include <list>
vandebo (ex-Chrome)
2012/09/05 00:58:12
Done.
| |
| 51 // TODO(vandebo) Check with prefs for permission to this gallery. | 59 |
| 52 return false; | 60 std::string RegisterFileSystem(std::string device_id, const FilePath& path) { |
| 61 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 62 | |
| 63 IsolatedContext* isolated_context = IsolatedContext::GetInstance(); | |
| 64 if (MediaStorageUtil::IsMassStorageDevice(device_id)) { | |
| 65 // Sanity checks for |path|. | |
| 66 CHECK(path.IsAbsolute()); | |
| 67 CHECK(!path.ReferencesParent()); | |
| 68 std::string fs_name(extension_misc::kMediaFileSystemPathPart); | |
| 69 const std::string fsid = isolated_context->RegisterFileSystemForPath( | |
| 70 fileapi::kFileSystemTypeNativeMedia, path, &fs_name); | |
| 71 CHECK(!fsid.empty()); | |
| 72 return fsid; | |
| 73 } | |
| 74 | |
| 75 // TODO(kmadhusu) handle MTP devices. | |
| 76 NOTREACHED(); | |
| 77 return std::string(); | |
| 53 } | 78 } |
| 54 | 79 |
| 55 } // namespace | 80 } // namespace |
| 56 | 81 |
| 82 // Refcounted only so it can easily be put in map. All instances are owned | |
| 83 // by |MediaFileSystemRegistry::extension_hosts_map_|. | |
| 84 class ExtensionGalleriesHost | |
| 85 : public base::RefCounted<ExtensionGalleriesHost>, | |
| 86 public content::NotificationObserver { | |
| 87 public: | |
| 88 // |no_references_callback| is called when the last RenderViewHost reference | |
| 89 // goes away. RenderViewHost references are added through ReferenceFromRVH(). | |
| 90 explicit ExtensionGalleriesHost(const base::Closure& no_references_callback) | |
| 91 : no_references_callback_(no_references_callback) { | |
| 92 } | |
| 93 | |
| 94 // For each galelry in the list of permitted |galleries|, looks up or creates | |
|
Lei Zhang
2012/09/04 23:38:51
nit: typo
vandebo (ex-Chrome)
2012/09/05 00:58:12
Done.
| |
| 95 // a file system id and returns the information needed for the renderer to | |
| 96 // create those file system objects. | |
| 97 std::vector<MediaFileSystemRegistry::MediaFSInfo> GetMediaFileSystems( | |
| 98 const MediaGalleryPrefIdSet& galleries, | |
| 99 const MediaGalleriesPrefInfoMap& galleries_info) { | |
| 100 std::vector<MediaFileSystemRegistry::MediaFSInfo> result; | |
| 101 for (std::set<MediaGalleryPrefId>::const_iterator id = galleries.begin(); | |
| 102 id != galleries.end(); | |
| 103 ++id) { | |
| 104 // TODO(vandebo) we also need to check that these galleries are attached. | |
| 105 PrefIdFsInfoMap::const_iterator existing_info = pref_id_map_.find(*id); | |
| 106 if (existing_info != pref_id_map_.end()) { | |
| 107 result.push_back(existing_info->second); | |
| 108 continue; | |
| 109 } | |
| 110 const MediaGalleryPrefInfo& gallery_info = | |
| 111 galleries_info.find(*id)->second; | |
| 112 const std::string& device_id = gallery_info.device_id; | |
| 113 // TODO(kmadhusu) handle MTP devices. | |
| 114 DCHECK(MediaStorageUtil::IsMassStorageDevice(device_id)); | |
| 115 FilePath path = MediaStorageUtil::FindDevicePathById(device_id); | |
| 116 CHECK(!path.empty()); | |
| 117 path = path.Append(gallery_info.path); | |
| 118 | |
| 119 MediaFileSystemRegistry::MediaFSInfo new_entry; | |
| 120 new_entry.name = gallery_info.display_name; | |
| 121 new_entry.path = path; | |
| 122 new_entry.fsid = RegisterFileSystem(device_id, path); | |
| 123 result.push_back(new_entry); | |
| 124 pref_id_map_[*id] = new_entry; | |
| 125 } | |
| 126 | |
| 127 // TODO(vandebo) We need a way of getting notification when permission for | |
| 128 // galleries are revoked (http://crbug.com/145855). For now, invalidate | |
| 129 // any fsid we have that we didn't get this time around. | |
| 130 if (galleries.size() != pref_id_map_.size()) { | |
| 131 MediaGalleryPrefIdSet old_galleries; | |
| 132 for (PrefIdFsInfoMap::const_iterator it = pref_id_map_.begin(); | |
| 133 it != pref_id_map_.end(); | |
| 134 ++it) { | |
| 135 old_galleries.insert(it->first); | |
| 136 } | |
| 137 MediaGalleryPrefIdSet invalid_galleries; | |
| 138 std::set_difference(old_galleries.begin(), old_galleries.end(), | |
| 139 galleries.begin(), galleries.end(), | |
| 140 std::inserter(invalid_galleries, | |
| 141 invalid_galleries.begin())); | |
| 142 for (MediaGalleryPrefIdSet::const_iterator it = invalid_galleries.begin(); | |
| 143 it != invalid_galleries.end(); | |
| 144 ++it) { | |
| 145 RevokeGalleryByPrefId(*it); | |
| 146 } | |
| 147 } | |
| 148 | |
| 149 return result; | |
| 150 } | |
| 151 | |
| 152 // Revoke the file system for |id| if this extension has created one for |id|. | |
| 153 void RevokeGalleryByPrefId(MediaGalleryPrefId id) { | |
| 154 PrefIdFsInfoMap::iterator gallery = pref_id_map_.find(id); | |
| 155 if (gallery == pref_id_map_.end()) | |
|
Lei Zhang
2012/09/04 23:38:51
Can this ever happen?
vandebo (ex-Chrome)
2012/09/05 00:58:12
Yes. If an extension doesn't have access to a rem
| |
| 156 return; | |
| 157 | |
| 158 IsolatedContext* isolated_context = IsolatedContext::GetInstance(); | |
| 159 isolated_context->RevokeFileSystem(gallery->second.fsid); | |
| 160 | |
| 161 pref_id_map_.erase(gallery); | |
| 162 } | |
| 163 | |
| 164 // Indicate that the passed render process will reference the file system | |
|
Lei Zhang
2012/09/04 23:38:51
render process -> rvh
vandebo (ex-Chrome)
2012/09/05 00:58:12
Done.
| |
| 165 // ids created by this class. It is safe to call this multiple times with | |
| 166 // the same RVH. | |
| 167 void ReferenceFromRVH(const content::RenderViewHost* rvh) { | |
| 168 WebContents* contents = WebContents::FromRenderViewHost(rvh); | |
| 169 if (registrar_.IsRegistered(this, | |
| 170 content::NOTIFICATION_WEB_CONTENTS_DESTROYED, | |
| 171 content::Source<WebContents>(contents))) { | |
| 172 return; | |
| 173 } | |
| 174 registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED, | |
| 175 content::Source<WebContents>(contents)); | |
| 176 registrar_.Add( | |
| 177 this, content::NOTIFICATION_NAV_ENTRY_COMMITTED, | |
| 178 content::Source<NavigationController>(&contents->GetController())); | |
| 179 | |
| 180 RenderProcessHost* rph = contents->GetRenderProcessHost(); | |
| 181 rph_refs_[rph].insert(contents); | |
| 182 if (rph_refs_[rph].size() == 1) { | |
| 183 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED, | |
| 184 content::Source<RenderProcessHost>(rph)); | |
| 185 } | |
| 186 } | |
| 187 | |
| 188 // NotificationObserver implementation. | |
| 189 virtual void Observe(int type, | |
| 190 const content::NotificationSource& source, | |
| 191 const content::NotificationDetails& details) OVERRIDE { | |
| 192 switch (type) { | |
| 193 case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: { | |
| 194 OnRendererProcessClosed( | |
| 195 content::Source<RenderProcessHost>(source).ptr()); | |
| 196 break; | |
| 197 } | |
| 198 case content::NOTIFICATION_WEB_CONTENTS_DESTROYED: { | |
| 199 OnWebContentsDestroyedOrNavigated( | |
| 200 content::Source<WebContents>(source).ptr()); | |
| 201 break; | |
| 202 } | |
| 203 case content::NOTIFICATION_NAV_ENTRY_COMMITTED: { | |
| 204 NavigationController* controller = | |
| 205 content::Source<NavigationController>(source).ptr(); | |
| 206 WebContents* contents = controller->GetWebContents(); | |
| 207 OnWebContentsDestroyedOrNavigated(contents); | |
| 208 break; | |
| 209 } | |
| 210 default: { | |
| 211 NOTREACHED(); | |
| 212 break; | |
| 213 } | |
| 214 } | |
| 215 } | |
| 216 | |
| 217 private: | |
| 218 typedef std::map<MediaGalleryPrefId, MediaFileSystemRegistry::MediaFSInfo> | |
| 219 PrefIdFsInfoMap; | |
| 220 typedef std::map<const RenderProcessHost*, std::set<const WebContents*> > | |
| 221 RenderProcessHostRefCount; | |
| 222 | |
| 223 // Private destructor and friend declaration for ref counted implementation. | |
| 224 friend class base::RefCounted<ExtensionGalleriesHost>; | |
|
Lei Zhang
2012/09/04 23:38:51
nit: blan line after this
vandebo (ex-Chrome)
2012/09/05 00:58:12
Done.
| |
| 225 virtual ~ExtensionGalleriesHost() { | |
| 226 DCHECK(rph_refs_.empty()); | |
| 227 DCHECK(pref_id_map_.empty()); | |
| 228 } | |
| 229 | |
| 230 void OnRendererProcessClosed(const RenderProcessHost* rph) { | |
| 231 RenderProcessHostRefCount::const_iterator rph_info = rph_refs_.find(rph); | |
| 232 DCHECK(rph_info != rph_refs_.end()); | |
| 233 // We're going to remove everything from the set, so we make a copy | |
| 234 // before operating on it. | |
| 235 std::set<const WebContents*> dead_rvhs = rph_info->second; | |
|
Lei Zhang
2012/09/04 23:38:51
|dead_rvhs| is weirdly named, since it's a set of
vandebo (ex-Chrome)
2012/09/05 00:58:12
Done.
| |
| 236 DCHECK(!dead_rvhs.empty()); | |
| 237 | |
| 238 for (std::set<const WebContents*>::const_iterator it = dead_rvhs.begin(); | |
| 239 it != dead_rvhs.end(); | |
| 240 ++it) { | |
| 241 OnWebContentsDestroyedOrNavigated(*it); | |
| 242 } | |
| 243 DCHECK(rph_refs_.find(rph) == rph_refs_.end()); | |
|
Lei Zhang
2012/09/04 23:38:51
You can use ContainsKey() here.
vandebo (ex-Chrome)
2012/09/05 00:58:12
Done.
| |
| 244 } | |
| 245 | |
| 246 void OnWebContentsDestroyedOrNavigated(const WebContents* contents) { | |
| 247 registrar_.Remove(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED, | |
| 248 content::Source<WebContents>(contents)); | |
| 249 registrar_.Remove( | |
| 250 this, content::NOTIFICATION_NAV_ENTRY_COMMITTED, | |
| 251 content::Source<NavigationController>(&contents->GetController())); | |
| 252 | |
| 253 RenderProcessHost* rph = contents->GetRenderProcessHost(); | |
| 254 rph_refs_[rph].erase(contents); | |
| 255 if (rph_refs_[rph].empty()) { | |
| 256 registrar_.Remove(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED, | |
| 257 content::Source<RenderProcessHost>(rph)); | |
| 258 rph_refs_.erase(rph); | |
| 259 } | |
| 260 | |
| 261 if (rph_refs_.empty()) { | |
| 262 IsolatedContext* isolated_context = IsolatedContext::GetInstance(); | |
| 263 for (PrefIdFsInfoMap::const_iterator it = pref_id_map_.begin(); | |
| 264 it != pref_id_map_.end(); | |
| 265 ++it) { | |
| 266 isolated_context->RevokeFileSystem(it->second.fsid); | |
| 267 } | |
| 268 pref_id_map_.clear(); | |
| 269 no_references_callback_.Run(); | |
| 270 } | |
| 271 } | |
| 272 | |
| 273 // A callback to call when the last RVH reference goes away. | |
| 274 base::Closure no_references_callback_; | |
| 275 | |
| 276 // A map from the gallery preferences id to the file system information. | |
| 277 PrefIdFsInfoMap pref_id_map_; | |
| 278 | |
| 279 // The set of render processes and web contents that may have references to | |
| 280 // the file system ids this instance manages. | |
| 281 RenderProcessHostRefCount rph_refs_; | |
| 282 | |
| 283 // A registrar for listening notifications. | |
| 284 content::NotificationRegistrar registrar_; | |
| 285 | |
| 286 DISALLOW_COPY_AND_ASSIGN(ExtensionGalleriesHost); | |
| 287 }; | |
| 57 | 288 |
| 58 /****************** | 289 /****************** |
| 59 * Public methods | 290 * Public methods |
| 60 ******************/ | 291 ******************/ |
| 61 | 292 |
| 62 // static | 293 // static |
| 63 MediaFileSystemRegistry* MediaFileSystemRegistry::GetInstance() { | 294 MediaFileSystemRegistry* MediaFileSystemRegistry::GetInstance() { |
| 64 return g_media_file_system_registry.Pointer(); | 295 return g_media_file_system_registry.Pointer(); |
| 65 } | 296 } |
| 66 | 297 |
| 298 // TODO(vandebo) We need to make this async so that we check that the | |
| 299 // galleries are attached (requires the file thread). | |
| 67 std::vector<MediaFileSystemRegistry::MediaFSInfo> | 300 std::vector<MediaFileSystemRegistry::MediaFSInfo> |
| 68 MediaFileSystemRegistry::GetMediaFileSystemsForExtension( | 301 MediaFileSystemRegistry::GetMediaFileSystemsForExtension( |
| 69 const content::RenderProcessHost* rph, | 302 const content::RenderViewHost* rvh, |
| 70 const extensions::Extension& extension) { | 303 const extensions::Extension* extension) { |
| 71 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 304 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 72 | 305 |
| 73 std::vector<MediaFSInfo> results; | 306 Profile* profile = |
| 74 std::pair<ChildIdToMediaFSMap::iterator, bool> ret = | 307 Profile::FromBrowserContext(rvh->GetProcess()->GetBrowserContext()); |
| 75 media_fs_map_.insert(std::make_pair(rph, MediaPathToFSIDMap())); | 308 MediaGalleriesPreferences* preferences = |
| 76 ChildIdToMediaFSMap::iterator& child_it = ret.first; | 309 MediaGalleriesPreferencesFactory::GetForProfile(profile); |
| 77 if (ret.second) { | 310 MediaGalleryPrefIdSet galleries = |
| 78 // Never seen a GetMediaFileSystems call from this RPH. Initialize its | 311 preferences->GalleriesForExtension(*extension); |
| 79 // file system mappings. | 312 ExtensionGalleriesHost* extension_host = |
| 80 RegisterForRPHGoneNotifications(rph); | 313 extension_hosts_map_[profile][extension->id()].get(); |
| 81 FilePath pictures_path; | 314 |
| 82 // TODO(vandebo) file system galleries need a unique id as well. | 315 if (galleries.empty() && !extension_host) |
|
Lei Zhang
2012/09/04 23:38:51
Can you comment what this case means?
"Never had a
vandebo (ex-Chrome)
2012/09/05 00:58:12
Done.
| |
| 83 if (PathService::Get(chrome::DIR_USER_PICTURES, &pictures_path) && | 316 return std::vector<MediaFileSystemRegistry::MediaFSInfo>(); |
| 84 IsGalleryPermittedForExtension(extension, pictures_path.value())) { | 317 |
| 85 std::string fsid = RegisterPathAsFileSystem(pictures_path); | 318 if (!extension_host) { |
|
Lei Zhang
2012/09/04 23:38:51
ditto, please comment.
"Has access to galleries, b
vandebo (ex-Chrome)
2012/09/05 00:58:12
I'm not sure this chunk of code needs a comment...
| |
| 86 child_it->second.insert(std::make_pair(pictures_path, fsid)); | 319 extension_hosts_map_[profile][extension->id()] = |
| 87 } | 320 new ExtensionGalleriesHost( |
| 321 base::Bind(&MediaFileSystemRegistry::OnExtensionGalleriesHostEmpty, | |
| 322 base::Unretained(this), profile, extension->id())); | |
| 323 extension_host = extension_hosts_map_[profile][extension->id()].get(); | |
| 88 } | 324 } |
| 325 extension_host->ReferenceFromRVH(rvh); | |
| 89 | 326 |
| 90 // TODO(thestig) Handle overlap between devices and media directories. | 327 return extension_host->GetMediaFileSystems(galleries, |
| 91 SystemMonitor* monitor = SystemMonitor::Get(); | 328 preferences->known_galleries()); |
| 92 const std::vector<SystemMonitor::RemovableStorageInfo> media_devices = | |
| 93 monitor->GetAttachedRemovableStorage(); | |
| 94 for (size_t i = 0; i < media_devices.size(); ++i) { | |
| 95 MediaStorageUtil::Type type; | |
| 96 MediaStorageUtil::CrackDeviceId(media_devices[i].device_id, &type, NULL); | |
| 97 // TODO(vandebo) Handle MTP devices. | |
| 98 if (type != MediaStorageUtil::MTP_OR_PTP && | |
| 99 IsGalleryPermittedForExtension(extension, media_devices[i].location)) { | |
| 100 device_id_map_.insert(std::make_pair(media_devices[i].device_id, | |
| 101 media_devices[i])); | |
| 102 FilePath path(media_devices[i].location); | |
| 103 const std::string fsid = RegisterPathAsFileSystem(path); | |
| 104 child_it->second.insert(std::make_pair(path, fsid)); | |
| 105 } | |
| 106 } | |
| 107 | |
| 108 MediaPathToFSIDMap& child_map = child_it->second; | |
| 109 for (MediaPathToFSIDMap::const_iterator it = child_map.begin(); | |
| 110 it != child_map.end(); | |
| 111 ++it) { | |
| 112 MediaFSInfo entry; | |
| 113 // TODO(vandebo) use a better name, fsid for now. | |
| 114 entry.name = it->second; | |
| 115 entry.fsid = it->second; | |
| 116 entry.path = it->first; | |
| 117 results.push_back(entry); | |
| 118 } | |
| 119 return results; | |
| 120 } | 329 } |
| 121 | 330 |
| 331 // TODO(vandebo) We also need to listen for the attach event and add newly | |
| 332 // attached media devices to MediaGalleriesPreferences. | |
| 122 void MediaFileSystemRegistry::OnRemovableStorageDetached( | 333 void MediaFileSystemRegistry::OnRemovableStorageDetached( |
| 123 const std::string& id) { | 334 const std::string& id) { |
| 124 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 335 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 125 | 336 |
| 126 DeviceIdToInfoMap::iterator it = device_id_map_.find(id); | 337 // Since revoking a gallery in the ExtensionGalleriesHost may cause it |
| 127 if (it == device_id_map_.end()) | 338 // to be removed from the map and therefore invalidate any iterator pointing |
| 128 return; | 339 // to it, we first make a list of all the ExtensionGalleriesHost*, pref_id |
| 340 // pairs to invalidate and then invalidate them in a second step. | |
| 341 InvalidatedGalleries invalidated_galleries; | |
| 129 | 342 |
| 130 FilePath path(it->second.location); | 343 for (ExtensionGalleriesHostMap::iterator extension_hosts_map_it = |
| 131 RevokeMediaFileSystem(path); | 344 extension_hosts_map_.begin(); |
| 132 device_id_map_.erase(it); | 345 extension_hosts_map_it != extension_hosts_map_.end(); |
| 133 } | 346 ++extension_hosts_map_it) { |
| 347 MediaGalleriesPreferences* preferences = | |
| 348 MediaGalleriesPreferencesFactory::GetForProfile( | |
| 349 extension_hosts_map_it->first); | |
| 350 MediaGalleryPrefIdSet detached_galleries = | |
| 351 preferences->LookUpGalleriesByDeviceId(id); | |
| 352 for (ExtensionHostMap::const_iterator extension_host_it = | |
|
Lei Zhang
2012/09/04 23:38:51
Do you think it'll be cleaner to put the second an
vandebo (ex-Chrome)
2012/09/05 00:58:12
I realized that this code was inefficient in that
| |
| 353 extension_hosts_map_it->second.begin(); | |
| 354 extension_host_it != extension_hosts_map_it->second.end(); | |
| 355 ++extension_host_it) { | |
| 356 for (MediaGalleryPrefIdSet::const_iterator pref_id = | |
| 357 detached_galleries.begin(); | |
| 358 pref_id != detached_galleries.end(); | |
| 359 ++pref_id) { | |
| 360 InvalidatedGallery gallery; | |
| 361 gallery.extension_host = extension_host_it->second.get(); | |
| 362 gallery.pref_id = *pref_id; | |
| 363 invalidated_galleries.push_back(gallery); | |
| 364 } | |
| 365 } | |
| 366 } | |
| 134 | 367 |
| 135 void MediaFileSystemRegistry::Observe( | 368 // TODO(kmadhusu, vandebo): Clean up this code. http://crbug.com/140340. |
| 136 int type, | 369 DCHECK(MediaStorageUtil::IsMassStorageDevice(id)); |
| 137 const content::NotificationSource& source, | 370 for (InvalidatedGalleries::const_iterator it = invalidated_galleries.begin(); |
| 138 const content::NotificationDetails& details) { | 371 it != invalidated_galleries.end(); |
| 139 DCHECK(type == content::NOTIFICATION_RENDERER_PROCESS_CLOSED || | 372 ++it) { |
| 140 type == content::NOTIFICATION_RENDERER_PROCESS_TERMINATED); | 373 it->extension_host->RevokeGalleryByPrefId(it->pref_id); |
| 141 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 374 } |
| 142 const RenderProcessHost* rph = | |
| 143 content::Source<content::RenderProcessHost>(source).ptr(); | |
| 144 ChildIdToMediaFSMap::iterator child_it = media_fs_map_.find(rph); | |
| 145 CHECK(child_it != media_fs_map_.end()); | |
| 146 // No need to revoke the isolated file systems. The RPH will do that. | |
| 147 media_fs_map_.erase(child_it); | |
| 148 UnregisterForRPHGoneNotifications(rph); | |
| 149 } | 375 } |
| 150 | 376 |
| 151 /****************** | 377 /****************** |
| 152 * Private methods | 378 * Private methods |
| 153 ******************/ | 379 ******************/ |
| 154 | 380 |
| 155 MediaFileSystemRegistry::MediaFileSystemRegistry() { | 381 MediaFileSystemRegistry::MediaFileSystemRegistry() { |
| 156 // SystemMonitor may be NULL in unit tests. | 382 // SystemMonitor may be NULL in unit tests. |
| 157 SystemMonitor* system_monitor = SystemMonitor::Get(); | 383 SystemMonitor* system_monitor = SystemMonitor::Get(); |
| 158 if (system_monitor) | 384 if (system_monitor) |
| 159 system_monitor->AddDevicesChangedObserver(this); | 385 system_monitor->AddDevicesChangedObserver(this); |
| 386 // TODO(vandebo) We should add all the currently attached media devices | |
| 387 // to MediaGalleriesPreferences here. | |
| 160 } | 388 } |
| 161 | 389 |
| 162 MediaFileSystemRegistry::~MediaFileSystemRegistry() { | 390 MediaFileSystemRegistry::~MediaFileSystemRegistry() { |
| 163 // SystemMonitor may be NULL in unit tests. | 391 // SystemMonitor may be NULL in unit tests. |
| 164 SystemMonitor* system_monitor = SystemMonitor::Get(); | 392 SystemMonitor* system_monitor = SystemMonitor::Get(); |
| 165 if (system_monitor) | 393 if (system_monitor) |
| 166 system_monitor->RemoveDevicesChangedObserver(this); | 394 system_monitor->RemoveDevicesChangedObserver(this); |
| 167 } | 395 } |
| 168 | 396 |
| 169 void MediaFileSystemRegistry::RegisterForRPHGoneNotifications( | 397 void MediaFileSystemRegistry::OnExtensionGalleriesHostEmpty( |
| 170 const content::RenderProcessHost* rph) { | 398 Profile* profile, const std::string& extension_id) { |
|
Lei Zhang
2012/09/04 23:38:51
Also DCHECK this is on the UI thread since we acce
vandebo (ex-Chrome)
2012/09/05 00:58:12
Done.
| |
| 171 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED, | 399 ExtensionGalleriesHostMap::iterator extension_hosts = |
| 172 content::Source<RenderProcessHost>(rph)); | 400 extension_hosts_map_.find(profile); |
| 173 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED, | 401 DCHECK(extension_hosts != extension_hosts_map_.end()); |
| 174 content::Source<RenderProcessHost>(rph)); | 402 ExtensionHostMap::size_type erase_count = |
| 175 } | 403 extension_hosts->second.erase(extension_id); |
| 176 | 404 DCHECK_EQ(1U, erase_count); |
| 177 void MediaFileSystemRegistry::UnregisterForRPHGoneNotifications( | 405 if (extension_hosts->second.empty()) |
| 178 const content::RenderProcessHost* rph) { | 406 extension_hosts_map_.erase(profile); |
| 179 registrar_.Remove(this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED, | |
| 180 content::Source<RenderProcessHost>(rph)); | |
| 181 registrar_.Remove(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED, | |
| 182 content::Source<RenderProcessHost>(rph)); | |
| 183 } | |
| 184 | |
| 185 std::string MediaFileSystemRegistry::RegisterPathAsFileSystem( | |
| 186 const FilePath& path) { | |
| 187 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 188 | |
| 189 // Sanity checks for |path|. | |
| 190 CHECK(path.IsAbsolute()); | |
| 191 CHECK(!path.ReferencesParent()); | |
| 192 | |
| 193 // The directory name is not exposed to the js layer and we simply use | |
| 194 // a fixed name (as we only register a single directory per file system). | |
| 195 std::string register_name(extension_misc::kMediaFileSystemPathPart); | |
| 196 const std::string fsid = | |
| 197 IsolatedContext::GetInstance()->RegisterFileSystemForPath( | |
| 198 fileapi::kFileSystemTypeNativeMedia, path, ®ister_name); | |
| 199 CHECK(!fsid.empty()); | |
| 200 return fsid; | |
| 201 } | |
| 202 | |
| 203 void MediaFileSystemRegistry::RevokeMediaFileSystem(const FilePath& path) { | |
| 204 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 205 | |
| 206 IsolatedContext* isolated_context = IsolatedContext::GetInstance(); | |
| 207 isolated_context->RevokeFileSystemByPath(path); | |
| 208 | |
| 209 for (ChildIdToMediaFSMap::iterator child_it = media_fs_map_.begin(); | |
| 210 child_it != media_fs_map_.end(); | |
| 211 ++child_it) { | |
| 212 MediaPathToFSIDMap& child_map = child_it->second; | |
| 213 MediaPathToFSIDMap::iterator media_path_it = child_map.find(path); | |
| 214 if (media_path_it == child_map.end()) | |
| 215 continue; | |
| 216 | |
| 217 child_map.erase(media_path_it); | |
| 218 } | |
| 219 } | 407 } |
| 220 | 408 |
| 221 } // namespace chrome | 409 } // namespace chrome |
| OLD | NEW |