Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / media_galleries / media_file_system_registry.cc
index 19c50f3..a53ed2b 100644 (file)
@@ -13,7 +13,7 @@
 #include "base/prefs/pref_service.h"
 #include "base/stl_util.h"
 #include "chrome/browser/extensions/extension_service.h"
-#include "chrome/browser/extensions/extension_system.h"
+#include "chrome/browser/media_galleries/fileapi/media_file_system_backend.h"
 #include "chrome/browser/media_galleries/fileapi/mtp_device_map_service.h"
 #include "chrome/browser/media_galleries/imported_media_gallery_registry.h"
 #include "chrome/browser/media_galleries/media_file_system_context.h"
 #include "chrome/browser/media_galleries/media_galleries_preferences_factory.h"
 #include "chrome/browser/media_galleries/media_scan_manager.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/storage_monitor/media_storage_util.h"
-#include "chrome/browser/storage_monitor/storage_monitor.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/extensions/extension_constants.h"
 #include "chrome/common/pref_names.h"
+#include "components/storage_monitor/media_storage_util.h"
+#include "components/storage_monitor/storage_monitor.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/navigation_details.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 "content/public/browser/web_contents_observer.h"
+#include "extensions/browser/extension_system.h"
 #include "extensions/common/extension.h"
 #include "extensions/common/extension_set.h"
-#include "webkit/browser/fileapi/isolated_context.h"
+#include "webkit/browser/fileapi/external_mount_points.h"
+#include "webkit/common/fileapi/file_system_mount_option.h"
 #include "webkit/common/fileapi/file_system_types.h"
 
 using content::BrowserThread;
 using content::NavigationController;
 using content::RenderProcessHost;
 using content::WebContents;
-using fileapi::IsolatedContext;
+using fileapi::ExternalMountPoints;
+using storage_monitor::MediaStorageUtil;
+using storage_monitor::StorageInfo;
+using storage_monitor::StorageMonitor;
 
 namespace {
 
@@ -80,7 +85,7 @@ class RPHReferenceManager {
 
    private:
     // content::WebContentsObserver
-    virtual void WebContentsDestroyed(WebContents* web_contents) OVERRIDE;
+    virtual void WebContentsDestroyed() OVERRIDE;
     virtual void NavigationEntryCommitted(
         const content::LoadCommittedDetails& load_details) OVERRIDE;
 
@@ -150,9 +155,8 @@ RPHReferenceManager::RPHWebContentsObserver::RPHWebContentsObserver(
       manager_(manager) {
 }
 
-void RPHReferenceManager::RPHWebContentsObserver::WebContentsDestroyed(
-    WebContents* web_contents) {
-  manager_->OnWebContentsDestroyedOrNavigated(web_contents);
+void RPHReferenceManager::RPHWebContentsObserver::WebContentsDestroyed() {
+  manager_->OnWebContentsDestroyedOrNavigated(web_contents());
 }
 
 void RPHReferenceManager::RPHWebContentsObserver::NavigationEntryCommitted(
@@ -258,15 +262,19 @@ class ExtensionGalleriesHost
   // |no_references_callback| is called when the last RenderViewHost reference
   // goes away. RenderViewHost references are added through ReferenceFromRVH().
   ExtensionGalleriesHost(MediaFileSystemContext* file_system_context,
+                         const base::FilePath& profile_path,
+                         const std::string& extension_id,
                          const base::Closure& no_references_callback)
       : file_system_context_(file_system_context),
+        profile_path_(profile_path),
+        extension_id_(extension_id),
         no_references_callback_(no_references_callback),
         rph_refs_(base::Bind(&ExtensionGalleriesHost::CleanUp,
                              base::Unretained(this))) {
   }
 
   // For each gallery in the list of permitted |galleries|, checks if the
-  // device is attached and if so looks up or creates a file system id and
+  // device is attached and if so looks up or creates a file system name and
   // passes the information needed for the renderer to create those file
   // system objects to the |callback|.
   void GetMediaFileSystems(const MediaGalleryPrefIdSet& galleries,
@@ -285,24 +293,18 @@ class ExtensionGalleriesHost
         base::Owned(device_ids), galleries, galleries_info, callback));
   }
 
-  void RevokeOldGalleries(const MediaGalleryPrefIdSet& new_galleries) {
-    if (new_galleries.size() == pref_id_map_.size())
-      return;
-
-    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 =
-        base::STLSetDifference<MediaGalleryPrefIdSet>(old_galleries,
-                                                      new_galleries);
-    for (MediaGalleryPrefIdSet::const_iterator it = invalid_galleries.begin();
-         it != invalid_galleries.end();
-         ++it) {
-      RevokeGalleryByPrefId(*it);
-    }
+  // Checks if |gallery| is attached and if so, registers the file system and
+  // then calls |callback| with the result.
+  void RegisterMediaFileSystem(
+      const MediaGalleryPrefInfo& gallery,
+      const base::Callback<void(base::File::Error result)>& callback) {
+    // Extract all the device ids so we can make sure they are attached.
+    MediaStorageUtil::DeviceIdSet* device_ids =
+        new MediaStorageUtil::DeviceIdSet;
+    device_ids->insert(gallery.device_id);
+    MediaStorageUtil::FilterAttachedDevices(device_ids, base::Bind(
+        &ExtensionGalleriesHost::RegisterAttachedMediaFileSystem, this,
+        base::Owned(device_ids), gallery, callback));
   }
 
   // Revoke the file system for |id| if this extension has created one for |id|.
@@ -352,7 +354,6 @@ class ExtensionGalleriesHost
       return;
     }
 
-    MediaGalleryPrefIdSet new_galleries;
     for (std::set<MediaGalleryPrefId>::const_iterator pref_id_it =
              galleries.begin();
          pref_id_it != galleries.end();
@@ -368,7 +369,6 @@ class ExtensionGalleriesHost
           pref_id_map_.find(pref_id);
       if (existing_info != pref_id_map_.end()) {
         result.push_back(existing_info->second);
-        new_galleries.insert(pref_id);
         continue;
       }
 
@@ -376,34 +376,72 @@ class ExtensionGalleriesHost
       if (!MediaStorageUtil::CanCreateFileSystem(device_id, path))
         continue;
 
-      std::string fsid =
-          file_system_context_->RegisterFileSystem(device_id, path);
-      if (fsid.empty())
+      std::string fs_name = MediaFileSystemBackend::ConstructMountName(
+          profile_path_, extension_id_, pref_id);
+      if (!file_system_context_->RegisterFileSystem(device_id, fs_name, path))
         continue;
 
       MediaFileSystemInfo new_entry(
           gallery_info.GetGalleryDisplayName(),
-          path,
-          fsid,
+          file_system_context_->GetRegisteredPath(fs_name),
+          fs_name,
           pref_id,
           GetTransientIdForRemovableDeviceId(device_id),
           StorageInfo::IsRemovableDevice(device_id),
           StorageInfo::IsMediaDevice(device_id));
       result.push_back(new_entry);
-      new_galleries.insert(pref_id);
       pref_id_map_[pref_id] = new_entry;
     }
 
     if (result.size() == 0) {
       rph_refs_.Reset();
       CleanUp();
-    } else {
-      RevokeOldGalleries(new_galleries);
     }
 
+    DCHECK_EQ(pref_id_map_.size(), result.size());
     callback.Run(result);
   }
 
+  void RegisterAttachedMediaFileSystem(
+      const MediaStorageUtil::DeviceIdSet* attached_device,
+      const MediaGalleryPrefInfo& gallery,
+      const base::Callback<void(base::File::Error result)>& callback) {
+    base::File::Error result = base::File::FILE_ERROR_NOT_FOUND;
+
+    // If rph_refs is empty then we're actually in the middle of shutdown, and
+    // Filter...() lagging which can invoke this method interleaved in the
+    // destruction callback sequence and re-populate pref_id_map_.
+    if (!attached_device->empty() && !rph_refs_.empty()) {
+      std::string fs_name = MediaFileSystemBackend::ConstructMountName(
+          profile_path_, extension_id_, gallery.pref_id);
+      base::FilePath path = gallery.AbsolutePath();
+      const std::string& device_id = gallery.device_id;
+
+      if (ContainsKey(pref_id_map_, gallery.pref_id)) {
+        result = base::File::FILE_OK;
+      } else if (MediaStorageUtil::CanCreateFileSystem(device_id, path) &&
+                 file_system_context_->RegisterFileSystem(device_id, fs_name,
+                                                          path)) {
+        result = base::File::FILE_OK;
+        pref_id_map_[gallery.pref_id] = MediaFileSystemInfo(
+            gallery.GetGalleryDisplayName(),
+            file_system_context_->GetRegisteredPath(fs_name),
+            fs_name,
+            gallery.pref_id,
+            GetTransientIdForRemovableDeviceId(device_id),
+            StorageInfo::IsRemovableDevice(device_id),
+            StorageInfo::IsMediaDevice(device_id));
+      }
+    }
+
+    if (pref_id_map_.empty()) {
+      rph_refs_.Reset();
+      CleanUp();
+    }
+    BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
+                            base::Bind(callback, result));
+  }
+
   std::string GetTransientIdForRemovableDeviceId(const std::string& device_id) {
     if (!StorageInfo::IsRemovableDevice(device_id))
       return std::string();
@@ -427,6 +465,12 @@ class ExtensionGalleriesHost
   // safe to store a raw pointer.
   MediaFileSystemContext* file_system_context_;
 
+  // Path for the active profile.
+  const base::FilePath profile_path_;
+
+  // Id of the extension this host belongs to.
+  const std::string extension_id_;
+
   // A callback to call when the last RVH reference goes away.
   base::Closure no_references_callback_;
 
@@ -448,7 +492,7 @@ void MediaFileSystemRegistry::GetMediaFileSystemsForExtension(
     const content::RenderViewHost* rvh,
     const extensions::Extension* extension,
     const MediaFileSystemsCallback& callback) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   Profile* profile =
       Profile::FromBrowserContext(rvh->GetProcess()->GetBrowserContext());
@@ -461,22 +505,9 @@ void MediaFileSystemRegistry::GetMediaFileSystemsForExtension(
     return;
   }
 
-  ExtensionGalleriesHostMap::iterator extension_hosts =
-      extension_hosts_map_.find(profile);
-  if (extension_hosts->second.empty())
-    preferences->AddGalleryChangeObserver(this);
-
   ExtensionGalleriesHost* extension_host =
-      extension_hosts->second[extension->id()].get();
-  if (!extension_host) {
-    extension_host = new ExtensionGalleriesHost(
-        file_system_context_.get(),
-        base::Bind(&MediaFileSystemRegistry::OnExtensionGalleriesHostEmpty,
-                   base::Unretained(this),
-                   profile,
-                   extension->id()));
-    extension_hosts_map_[profile][extension->id()] = extension_host;
-  }
+      GetExtensionGalleryHost(profile, preferences, extension->id());
+
   // This must come before the GetMediaFileSystems call to make sure the
   // RVH of the context is referenced before the filesystems are retrieved.
   extension_host->ReferenceFromRVH(rvh);
@@ -485,12 +516,47 @@ void MediaFileSystemRegistry::GetMediaFileSystemsForExtension(
                                       callback);
 }
 
+void MediaFileSystemRegistry::RegisterMediaFileSystemForExtension(
+    const content::RenderViewHost* rvh,
+    const extensions::Extension* extension,
+    MediaGalleryPrefId pref_id,
+    const base::Callback<void(base::File::Error result)>& callback) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK_NE(kInvalidMediaGalleryPrefId, pref_id);
+
+  Profile* profile =
+      Profile::FromBrowserContext(rvh->GetProcess()->GetBrowserContext());
+  MediaGalleriesPreferences* preferences = GetPreferences(profile);
+  MediaGalleriesPrefInfoMap::const_iterator gallery =
+      preferences->known_galleries().find(pref_id);
+  MediaGalleryPrefIdSet permitted_galleries =
+      preferences->GalleriesForExtension(*extension);
+
+  if (gallery == preferences->known_galleries().end() ||
+      !ContainsKey(permitted_galleries, pref_id)) {
+    BrowserThread::PostTask(
+        BrowserThread::IO, FROM_HERE,
+        base::Bind(callback, base::File::FILE_ERROR_NOT_FOUND));
+    return;
+  }
+
+  ExtensionGalleriesHost* extension_host =
+      GetExtensionGalleryHost(profile, preferences, extension->id());
+
+  // This must come before the GetMediaFileSystems call to make sure the
+  // RVH of the context is referenced before the filesystems are retrieved.
+  extension_host->ReferenceFromRVH(rvh);
+
+  extension_host->RegisterMediaFileSystem(gallery->second, callback);
+}
+
 MediaGalleriesPreferences* MediaFileSystemRegistry::GetPreferences(
     Profile* profile) {
   // Create an empty ExtensionHostMap for this profile on first initialization.
-  if (!ContainsKey(extension_hosts_map_, profile))
+  if (!ContainsKey(extension_hosts_map_, profile)) {
     extension_hosts_map_[profile] = ExtensionHostMap();
-  media_galleries::UsageCount(media_galleries::PROFILES_WITH_USAGE);
+    media_galleries::UsageCount(media_galleries::PROFILES_WITH_USAGE);
+  }
 
   return MediaGalleriesPreferencesFactory::GetForProfile(profile);
 }
@@ -503,7 +569,7 @@ MediaScanManager* MediaFileSystemRegistry::media_scan_manager() {
 
 void MediaFileSystemRegistry::OnRemovableStorageDetached(
     const StorageInfo& info) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   // Since revoking a gallery in the ExtensionGalleriesHost may cause it
   // to be removed from the map and therefore invalidate any iterator pointing
@@ -558,42 +624,50 @@ void MediaFileSystemRegistry::OnRemovableStorageDetached(
 class MediaFileSystemRegistry::MediaFileSystemContextImpl
     : public MediaFileSystemContext {
  public:
-  explicit MediaFileSystemContextImpl(MediaFileSystemRegistry* registry)
-      : registry_(registry) {
-    DCHECK(registry_);  // Suppresses unused warning on Android.
-  }
+  MediaFileSystemContextImpl() {}
   virtual ~MediaFileSystemContextImpl() {}
 
-  virtual std::string RegisterFileSystem(
-      const std::string& device_id, const base::FilePath& path) OVERRIDE {
+  virtual bool RegisterFileSystem(const std::string& device_id,
+                                  const std::string& fs_name,
+                                  const base::FilePath& path) OVERRIDE {
     if (StorageInfo::IsMassStorageDevice(device_id)) {
-      return RegisterFileSystemForMassStorage(device_id, path);
+      return RegisterFileSystemForMassStorage(device_id, fs_name, path);
     } else {
-      return RegisterFileSystemForMTPDevice(device_id, path);
+      return RegisterFileSystemForMTPDevice(device_id, fs_name, path);
     }
   }
 
-  virtual void RevokeFileSystem(const std::string& fsid) OVERRIDE {
+  virtual void RevokeFileSystem(const std::string& fs_name) OVERRIDE {
     ImportedMediaGalleryRegistry* imported_registry =
         ImportedMediaGalleryRegistry::GetInstance();
-    if (imported_registry->RevokeImportedFilesystemOnUIThread(fsid))
+    if (imported_registry->RevokeImportedFilesystemOnUIThread(fs_name))
       return;
 
-    IsolatedContext::GetInstance()->RevokeFileSystem(fsid);
+    ExternalMountPoints::GetSystemInstance()->RevokeFileSystem(fs_name);
 
-    content::BrowserThread::PostTask(
-        content::BrowserThread::IO, FROM_HERE, base::Bind(
-            &MTPDeviceMapService::RevokeMTPFileSystem,
-            base::Unretained(MTPDeviceMapService::GetInstance()),
-            fsid));
+    BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, base::Bind(
+        &MTPDeviceMapService::RevokeMTPFileSystem,
+        base::Unretained(MTPDeviceMapService::GetInstance()),
+        fs_name));
+  }
+
+  virtual base::FilePath GetRegisteredPath(
+      const std::string& fs_name) const OVERRIDE {
+    base::FilePath result;
+    if (!ExternalMountPoints::GetSystemInstance()->GetRegisteredPath(fs_name,
+                                                                     &result)) {
+      return base::FilePath();
+    }
+    return result;
   }
 
  private:
   // Registers and returns the file system id for the mass storage device
   // specified by |device_id| and |path|.
-  std::string RegisterFileSystemForMassStorage(
-      const std::string& device_id, const base::FilePath& path) {
-    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  bool RegisterFileSystemForMassStorage(const std::string& device_id,
+                                        const std::string& fs_name,
+                                        const base::FilePath& path) {
+    DCHECK_CURRENTLY_ON(BrowserThread::UI);
     DCHECK(StorageInfo::IsMassStorageDevice(device_id));
 
     // Sanity checks for |path|.
@@ -604,57 +678,52 @@ class MediaFileSystemRegistry::MediaFileSystemContextImpl
     // call tree, probably by having it figure out by device id what
     // registration is needed, or having per-device-type handlers at the
     // next higher level.
-    std::string fsid;
+    bool result = false;
     if (StorageInfo::IsITunesDevice(device_id)) {
-      ImportedMediaGalleryRegistry* imported_registry =
+      ImportedMediaGalleryRegistry* registry =
           ImportedMediaGalleryRegistry::GetInstance();
-      fsid = imported_registry->RegisterITunesFilesystemOnUIThread(path);
+      result = registry->RegisterITunesFilesystemOnUIThread(fs_name, path);
     } else if (StorageInfo::IsPicasaDevice(device_id)) {
-      ImportedMediaGalleryRegistry* imported_registry =
+      ImportedMediaGalleryRegistry* registry =
           ImportedMediaGalleryRegistry::GetInstance();
-      fsid = imported_registry->RegisterPicasaFilesystemOnUIThread(
-          path);
+      result = registry->RegisterPicasaFilesystemOnUIThread(fs_name, path);
     } else if (StorageInfo::IsIPhotoDevice(device_id)) {
-      ImportedMediaGalleryRegistry* imported_registry =
+      ImportedMediaGalleryRegistry* registry =
           ImportedMediaGalleryRegistry::GetInstance();
-      fsid = imported_registry->RegisterIPhotoFilesystemOnUIThread(
-          path);
+      result = registry->RegisterIPhotoFilesystemOnUIThread(fs_name, path);
     } else {
-      std::string fs_name(extension_misc::kMediaFileSystemPathPart);
-      fsid = IsolatedContext::GetInstance()->RegisterFileSystemForPath(
-          fileapi::kFileSystemTypeNativeMedia, path, &fs_name);
+      result = ExternalMountPoints::GetSystemInstance()->RegisterFileSystem(
+          fs_name, fileapi::kFileSystemTypeNativeMedia,
+          fileapi::FileSystemMountOption(), path);
     }
-    return fsid;
+    return result;
   }
 
-  std::string RegisterFileSystemForMTPDevice(
-      const std::string& device_id, const base::FilePath& path) {
-    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  bool RegisterFileSystemForMTPDevice(const std::string& device_id,
+                                      const std::string fs_name,
+                                      const base::FilePath& path) {
+    DCHECK_CURRENTLY_ON(BrowserThread::UI);
     DCHECK(!StorageInfo::IsMassStorageDevice(device_id));
 
     // Sanity checks for |path|.
     CHECK(MediaStorageUtil::CanCreateFileSystem(device_id, path));
-    std::string fs_name(extension_misc::kMediaFileSystemPathPart);
-    const std::string fsid =
-        IsolatedContext::GetInstance()->RegisterFileSystemForPath(
-            fileapi::kFileSystemTypeDeviceMedia, path, &fs_name);
-    CHECK(!fsid.empty());
-    content::BrowserThread::PostTask(
-        content::BrowserThread::IO, FROM_HERE, base::Bind(
-            &MTPDeviceMapService::RegisterMTPFileSystem,
-            base::Unretained(MTPDeviceMapService::GetInstance()),
-            path.value(), fsid));
-    return fsid;
+    bool result = ExternalMountPoints::GetSystemInstance()->RegisterFileSystem(
+        fs_name, fileapi::kFileSystemTypeDeviceMedia,
+        fileapi::FileSystemMountOption(), path);
+    CHECK(result);
+    BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, base::Bind(
+        &MTPDeviceMapService::RegisterMTPFileSystem,
+        base::Unretained(MTPDeviceMapService::GetInstance()),
+        path.value(), fs_name));
+    return result;
   }
 
-  MediaFileSystemRegistry* registry_;
-
   DISALLOW_COPY_AND_ASSIGN(MediaFileSystemContextImpl);
 };
 
 // Constructor in 'private' section because depends on private class definition.
 MediaFileSystemRegistry::MediaFileSystemRegistry()
-    : file_system_context_(new MediaFileSystemContextImpl(this)) {
+    : file_system_context_(new MediaFileSystemContextImpl) {
   StorageMonitor::GetInstance()->AddObserver(this);
 }
 
@@ -718,9 +787,36 @@ void MediaFileSystemRegistry::OnGalleryRemoved(
   }
 }
 
+ExtensionGalleriesHost* MediaFileSystemRegistry::GetExtensionGalleryHost(
+    Profile* profile,
+    MediaGalleriesPreferences* preferences,
+    const std::string& extension_id) {
+  ExtensionGalleriesHostMap::iterator extension_hosts =
+      extension_hosts_map_.find(profile);
+  // GetPreferences(), which had to be called because preferences is an
+  // argument, ensures that profile is in the map.
+  DCHECK(extension_hosts != extension_hosts_map_.end());
+  if (extension_hosts->second.empty())
+    preferences->AddGalleryChangeObserver(this);
+
+  ExtensionGalleriesHost* result = extension_hosts->second[extension_id].get();
+  if (!result) {
+    result = new ExtensionGalleriesHost(
+        file_system_context_.get(),
+        profile->GetPath(),
+        extension_id,
+        base::Bind(&MediaFileSystemRegistry::OnExtensionGalleriesHostEmpty,
+                   base::Unretained(this),
+                   profile,
+                   extension_id));
+    extension_hosts_map_[profile][extension_id] = result;
+  }
+  return result;
+}
+
 void MediaFileSystemRegistry::OnExtensionGalleriesHostEmpty(
     Profile* profile, const std::string& extension_id) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   ExtensionGalleriesHostMap::iterator extension_hosts =
       extension_hosts_map_.find(profile);