| 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. | |
| 6 | |
| 7 #include "chrome/browser/media_galleries/media_file_system_registry.h" | 5 #include "chrome/browser/media_galleries/media_file_system_registry.h" |
| 8 | 6 |
| 9 #include <set> | 7 #include <set> |
| 10 #include <vector> | 8 #include <vector> |
| 11 | 9 |
| 12 #include "base/bind.h" | 10 #include "base/bind.h" |
| 13 #include "base/callback.h" | 11 #include "base/callback.h" |
| 14 #include "base/files/file_path.h" | 12 #include "base/files/file_path.h" |
| 15 #include "base/prefs/pref_service.h" | 13 #include "base/prefs/pref_service.h" |
| 16 #include "base/stl_util.h" | 14 #include "base/stl_util.h" |
| 17 #include "chrome/browser/chrome_notification_types.h" | |
| 18 #include "chrome/browser/extensions/extension_service.h" | 15 #include "chrome/browser/extensions/extension_service.h" |
| 19 #include "chrome/browser/extensions/extension_system.h" | 16 #include "chrome/browser/extensions/extension_system.h" |
| 20 #include "chrome/browser/media_galleries/fileapi/mtp_device_map_service.h" | 17 #include "chrome/browser/media_galleries/fileapi/mtp_device_map_service.h" |
| 21 #include "chrome/browser/media_galleries/imported_media_gallery_registry.h" | 18 #include "chrome/browser/media_galleries/imported_media_gallery_registry.h" |
| 22 #include "chrome/browser/media_galleries/media_file_system_context.h" | 19 #include "chrome/browser/media_galleries/media_file_system_context.h" |
| 23 #include "chrome/browser/media_galleries/media_galleries_dialog_controller.h" | 20 #include "chrome/browser/media_galleries/media_galleries_dialog_controller.h" |
| 24 #include "chrome/browser/media_galleries/media_galleries_histograms.h" | 21 #include "chrome/browser/media_galleries/media_galleries_histograms.h" |
| 25 #include "chrome/browser/media_galleries/media_galleries_preferences_factory.h" | 22 #include "chrome/browser/media_galleries/media_galleries_preferences_factory.h" |
| 26 #include "chrome/browser/profiles/profile.h" | 23 #include "chrome/browser/profiles/profile.h" |
| 27 #include "chrome/browser/storage_monitor/media_storage_util.h" | 24 #include "chrome/browser/storage_monitor/media_storage_util.h" |
| 28 #include "chrome/browser/storage_monitor/storage_monitor.h" | 25 #include "chrome/browser/storage_monitor/storage_monitor.h" |
| 29 #include "chrome/common/chrome_paths.h" | 26 #include "chrome/common/chrome_paths.h" |
| 30 #include "chrome/common/extensions/extension_constants.h" | 27 #include "chrome/common/extensions/extension_constants.h" |
| 31 #include "chrome/common/pref_names.h" | 28 #include "chrome/common/pref_names.h" |
| 32 #include "content/public/browser/browser_thread.h" | 29 #include "content/public/browser/browser_thread.h" |
| 33 #include "content/public/browser/navigation_details.h" | 30 #include "content/public/browser/navigation_details.h" |
| 34 #include "content/public/browser/notification_details.h" | |
| 35 #include "content/public/browser/notification_observer.h" | |
| 36 #include "content/public/browser/notification_registrar.h" | |
| 37 #include "content/public/browser/notification_source.h" | |
| 38 #include "content/public/browser/notification_types.h" | |
| 39 #include "content/public/browser/render_process_host.h" | 31 #include "content/public/browser/render_process_host.h" |
| 32 #include "content/public/browser/render_process_host_observer.h" |
| 40 #include "content/public/browser/render_view_host.h" | 33 #include "content/public/browser/render_view_host.h" |
| 41 #include "content/public/browser/web_contents.h" | 34 #include "content/public/browser/web_contents.h" |
| 35 #include "content/public/browser/web_contents_observer.h" |
| 42 #include "extensions/common/extension.h" | 36 #include "extensions/common/extension.h" |
| 43 #include "extensions/common/extension_set.h" | 37 #include "extensions/common/extension_set.h" |
| 44 #include "webkit/browser/fileapi/isolated_context.h" | 38 #include "webkit/browser/fileapi/isolated_context.h" |
| 45 #include "webkit/common/fileapi/file_system_types.h" | 39 #include "webkit/common/fileapi/file_system_types.h" |
| 46 | 40 |
| 47 using content::BrowserThread; | 41 using content::BrowserThread; |
| 48 using content::NavigationController; | 42 using content::NavigationController; |
| 49 using content::RenderProcessHost; | 43 using content::RenderProcessHost; |
| 50 using content::WebContents; | 44 using content::WebContents; |
| 51 using fileapi::IsolatedContext; | 45 using fileapi::IsolatedContext; |
| 52 | 46 |
| 53 namespace { | 47 namespace { |
| 54 | 48 |
| 55 struct InvalidatedGalleriesInfo { | 49 struct InvalidatedGalleriesInfo { |
| 56 std::set<ExtensionGalleriesHost*> extension_hosts; | 50 std::set<ExtensionGalleriesHost*> extension_hosts; |
| 57 std::set<MediaGalleryPrefId> pref_ids; | 51 std::set<MediaGalleryPrefId> pref_ids; |
| 58 }; | 52 }; |
| 59 | 53 |
| 60 // Tracks the liveness of multiple RenderProcessHosts that the caller is | 54 // Tracks the liveness of multiple RenderProcessHosts that the caller is |
| 61 // interested in. Once all of the RPHs have closed or been terminated a call | 55 // interested in. Once all of the RPHs have closed or been destroyed a call |
| 62 // back informs the caller. | 56 // back informs the caller. |
| 63 class RPHReferenceManager : public content::NotificationObserver { | 57 class RPHReferenceManager { |
| 64 public: | 58 public: |
| 65 // |no_references_callback| is called when the last RenderViewHost reference | 59 // |no_references_callback| is called when the last RenderViewHost reference |
| 66 // goes away. RenderViewHost references are added through ReferenceFromRVH(). | 60 // goes away. RenderViewHost references are added through ReferenceFromRVH(). |
| 67 explicit RPHReferenceManager(const base::Closure& no_references_callback) | 61 explicit RPHReferenceManager(const base::Closure& no_references_callback); |
| 68 : no_references_callback_(no_references_callback) { | 62 virtual ~RPHReferenceManager(); |
| 69 } | |
| 70 | |
| 71 virtual ~RPHReferenceManager() { | |
| 72 Reset(); | |
| 73 } | |
| 74 | 63 |
| 75 // Remove all references, but don't call |no_references_callback|. | 64 // Remove all references, but don't call |no_references_callback|. |
| 76 void Reset() { | 65 void Reset() { STLDeleteValues(&observer_map_); } |
| 77 STLDeleteValues(&refs_); | |
| 78 } | |
| 79 | 66 |
| 80 // Returns true if there are no references; | 67 // Returns true if there are no references; |
| 81 bool empty() const { | 68 bool empty() const { return observer_map_.empty(); } |
| 82 return refs_.empty(); | |
| 83 } | |
| 84 | 69 |
| 85 // Adds a reference to the passed |rvh|. Calling this multiple times with | 70 // Adds a reference to the passed |rvh|. Calling this multiple times with |
| 86 // the same |rvh| is a no-op. | 71 // the same |rvh| is a no-op. |
| 87 void ReferenceFromRVH(const content::RenderViewHost* rvh) { | 72 void ReferenceFromRVH(const content::RenderViewHost* rvh); |
| 88 WebContents* contents = WebContents::FromRenderViewHost(rvh); | 73 |
| 89 RenderProcessHost* rph = contents->GetRenderProcessHost(); | 74 private: |
| 90 RPHReferenceState* state = NULL; | 75 class RPHWebContentsObserver : public content::WebContentsObserver { |
| 91 if (!ContainsKey(refs_, rph)) { | 76 public: |
| 92 state = new RPHReferenceState; | 77 RPHWebContentsObserver(RPHReferenceManager* manager, |
| 93 refs_[rph] = state; | 78 WebContents* web_contents); |
| 94 state->registrar.Add( | 79 |
| 95 this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED, | 80 private: |
| 96 content::Source<RenderProcessHost>(rph)); | 81 // content::WebContentsObserver |
| 97 } else { | 82 virtual void WebContentsDestroyed(WebContents* web_contents) OVERRIDE; |
| 98 state = refs_[rph]; | 83 virtual void NavigationEntryCommitted( |
| 84 const content::LoadCommittedDetails& load_details) OVERRIDE; |
| 85 |
| 86 RPHReferenceManager* manager_; |
| 87 }; |
| 88 |
| 89 class RPHObserver : public content::RenderProcessHostObserver { |
| 90 public: |
| 91 RPHObserver(RPHReferenceManager* manager, RenderProcessHost* host); |
| 92 virtual ~RPHObserver(); |
| 93 |
| 94 void AddWebContentsObserver(WebContents* web_contents); |
| 95 void RemoveWebContentsObserver(WebContents* web_contents); |
| 96 bool HasWebContentsObservers() { |
| 97 return observed_web_contentses_.size() > 0; |
| 99 } | 98 } |
| 100 | 99 |
| 101 if (state->web_contents_set.insert(contents).second) { | 100 private: |
| 102 state->registrar.Add(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED, | 101 virtual void RenderProcessHostDestroyed(RenderProcessHost* host) OVERRIDE; |
| 103 content::Source<WebContents>(contents)); | |
| 104 state->registrar.Add(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED, | |
| 105 content::Source<NavigationController>(&contents->GetController())); | |
| 106 } | |
| 107 } | |
| 108 | 102 |
| 109 private: | 103 RPHReferenceManager* manager_; |
| 110 struct RPHReferenceState { | 104 RenderProcessHost* host_; |
| 111 content::NotificationRegistrar registrar; | 105 typedef std::map<WebContents*, RPHWebContentsObserver*> WCObserverMap; |
| 112 std::set<const WebContents*> web_contents_set; | 106 WCObserverMap observed_web_contentses_; |
| 113 }; | 107 }; |
| 114 typedef std::map<const RenderProcessHost*, RPHReferenceState*> RPHRefCount; | 108 typedef std::map<const RenderProcessHost*, RPHObserver*> RPHObserverMap; |
| 115 | 109 |
| 116 // NotificationObserver implementation. | 110 // Handlers for observed events. |
| 117 virtual void Observe(int type, | 111 void OnRenderProcessHostDestroyed(RenderProcessHost* rph); |
| 118 const content::NotificationSource& source, | 112 void OnWebContentsDestroyedOrNavigated(WebContents* contents); |
| 119 const content::NotificationDetails& details) OVERRIDE { | |
| 120 switch (type) { | |
| 121 case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED: { | |
| 122 OnRendererProcessTerminated( | |
| 123 content::Source<RenderProcessHost>(source).ptr()); | |
| 124 break; | |
| 125 } | |
| 126 case content::NOTIFICATION_WEB_CONTENTS_DESTROYED: { | |
| 127 OnWebContentsDestroyedOrNavigated( | |
| 128 content::Source<WebContents>(source).ptr()); | |
| 129 break; | |
| 130 } | |
| 131 case content::NOTIFICATION_NAV_ENTRY_COMMITTED: { | |
| 132 content::LoadCommittedDetails* load_details = | |
| 133 content::Details<content::LoadCommittedDetails>(details).ptr(); | |
| 134 if (load_details->is_in_page) | |
| 135 break; | |
| 136 NavigationController* controller = | |
| 137 content::Source<NavigationController>(source).ptr(); | |
| 138 WebContents* contents = controller->GetWebContents(); | |
| 139 OnWebContentsDestroyedOrNavigated(contents); | |
| 140 break; | |
| 141 } | |
| 142 default: { | |
| 143 NOTREACHED(); | |
| 144 break; | |
| 145 } | |
| 146 } | |
| 147 } | |
| 148 | |
| 149 void OnRendererProcessTerminated(const RenderProcessHost* rph) { | |
| 150 RPHRefCount::iterator rph_info = refs_.find(rph); | |
| 151 // This could be a potential problem if the RPH is navigated to | |
| 152 // a page on the same renderer (triggering OWCDON()) and then | |
| 153 // the renderer crashes. | |
| 154 if (rph_info == refs_.end()) { | |
| 155 NOTREACHED(); | |
| 156 return; | |
| 157 } | |
| 158 | |
| 159 delete rph_info->second; | |
| 160 refs_.erase(rph_info); | |
| 161 if (refs_.empty()) | |
| 162 no_references_callback_.Run(); | |
| 163 } | |
| 164 | |
| 165 void OnWebContentsDestroyedOrNavigated(const WebContents* contents) { | |
| 166 RenderProcessHost* rph = contents->GetRenderProcessHost(); | |
| 167 RPHRefCount::iterator rph_info = refs_.find(rph); | |
| 168 DCHECK(rph_info != refs_.end()); | |
| 169 | |
| 170 rph_info->second->registrar.Remove( | |
| 171 this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED, | |
| 172 content::Source<WebContents>(contents)); | |
| 173 rph_info->second->registrar.Remove( | |
| 174 this, content::NOTIFICATION_NAV_ENTRY_COMMITTED, | |
| 175 content::Source<NavigationController>(&contents->GetController())); | |
| 176 | |
| 177 rph_info->second->web_contents_set.erase(contents); | |
| 178 if (rph_info->second->web_contents_set.empty()) | |
| 179 OnRendererProcessTerminated(rph); | |
| 180 } | |
| 181 | 113 |
| 182 // A callback to call when the last RVH reference goes away. | 114 // A callback to call when the last RVH reference goes away. |
| 183 base::Closure no_references_callback_; | 115 base::Closure no_references_callback_; |
| 184 | 116 |
| 185 // The set of render processes and web contents that may have references to | 117 // The set of render processes and web contents that may have references to |
| 186 // the file system ids this instance manages. | 118 // the file system ids this instance manages. |
| 187 RPHRefCount refs_; | 119 RPHObserverMap observer_map_; |
| 188 }; | 120 }; |
| 189 | 121 |
| 122 RPHReferenceManager::RPHReferenceManager( |
| 123 const base::Closure& no_references_callback) |
| 124 : no_references_callback_(no_references_callback) { |
| 125 } |
| 126 |
| 127 RPHReferenceManager::~RPHReferenceManager() { |
| 128 Reset(); |
| 129 } |
| 130 |
| 131 void RPHReferenceManager::ReferenceFromRVH(const content::RenderViewHost* rvh) { |
| 132 WebContents* contents = WebContents::FromRenderViewHost(rvh); |
| 133 RenderProcessHost* rph = contents->GetRenderProcessHost(); |
| 134 RPHObserver* state = NULL; |
| 135 if (!ContainsKey(observer_map_, rph)) { |
| 136 state = new RPHObserver(this, rph); |
| 137 observer_map_[rph] = state; |
| 138 } else { |
| 139 state = observer_map_[rph]; |
| 140 } |
| 141 |
| 142 state->AddWebContentsObserver(contents); |
| 143 } |
| 144 |
| 145 RPHReferenceManager::RPHWebContentsObserver::RPHWebContentsObserver( |
| 146 RPHReferenceManager* manager, |
| 147 WebContents* web_contents) |
| 148 : content::WebContentsObserver(web_contents), |
| 149 manager_(manager) { |
| 150 } |
| 151 |
| 152 void RPHReferenceManager::RPHWebContentsObserver::WebContentsDestroyed( |
| 153 WebContents* web_contents) { |
| 154 manager_->OnWebContentsDestroyedOrNavigated(web_contents); |
| 155 } |
| 156 |
| 157 void RPHReferenceManager::RPHWebContentsObserver::NavigationEntryCommitted( |
| 158 const content::LoadCommittedDetails& load_details) { |
| 159 if (load_details.is_in_page) |
| 160 return; |
| 161 |
| 162 manager_->OnWebContentsDestroyedOrNavigated(web_contents()); |
| 163 } |
| 164 |
| 165 RPHReferenceManager::RPHObserver::RPHObserver( |
| 166 RPHReferenceManager* manager, RenderProcessHost* host) |
| 167 : manager_(manager), |
| 168 host_(host) { |
| 169 host->AddObserver(this); |
| 170 } |
| 171 |
| 172 RPHReferenceManager::RPHObserver::~RPHObserver() { |
| 173 STLDeleteValues(&observed_web_contentses_); |
| 174 if (host_) |
| 175 host_->RemoveObserver(this); |
| 176 } |
| 177 |
| 178 void RPHReferenceManager::RPHObserver::AddWebContentsObserver( |
| 179 WebContents* web_contents) { |
| 180 if (ContainsKey(observed_web_contentses_, web_contents)) |
| 181 return; |
| 182 |
| 183 RPHWebContentsObserver* observer = |
| 184 new RPHWebContentsObserver(manager_, web_contents); |
| 185 observed_web_contentses_[web_contents] = observer; |
| 186 } |
| 187 |
| 188 void RPHReferenceManager::RPHObserver::RemoveWebContentsObserver( |
| 189 WebContents* web_contents) { |
| 190 WCObserverMap::iterator wco_iter = |
| 191 observed_web_contentses_.find(web_contents); |
| 192 DCHECK(wco_iter != observed_web_contentses_.end()); |
| 193 delete wco_iter->second; |
| 194 observed_web_contentses_.erase(wco_iter); |
| 195 } |
| 196 |
| 197 void RPHReferenceManager::RPHObserver::RenderProcessHostDestroyed( |
| 198 RenderProcessHost* host) { |
| 199 host_ = NULL; |
| 200 manager_->OnRenderProcessHostDestroyed(host); |
| 201 } |
| 202 |
| 203 void RPHReferenceManager::OnRenderProcessHostDestroyed( |
| 204 RenderProcessHost* rph) { |
| 205 RPHObserverMap::iterator rph_info = observer_map_.find(rph); |
| 206 // This could be a potential problem if the RPH is navigated to a page on the |
| 207 // same renderer (triggering OnWebContentsDestroyedOrNavigated()) and then the |
| 208 // renderer crashes. |
| 209 if (rph_info == observer_map_.end()) { |
| 210 NOTREACHED(); |
| 211 return; |
| 212 } |
| 213 delete rph_info->second; |
| 214 observer_map_.erase(rph_info); |
| 215 if (observer_map_.empty()) |
| 216 no_references_callback_.Run(); |
| 217 } |
| 218 |
| 219 void RPHReferenceManager::OnWebContentsDestroyedOrNavigated( |
| 220 WebContents* contents) { |
| 221 RenderProcessHost* rph = contents->GetRenderProcessHost(); |
| 222 RPHObserverMap::iterator rph_info = observer_map_.find(rph); |
| 223 DCHECK(rph_info != observer_map_.end()); |
| 224 |
| 225 rph_info->second->RemoveWebContentsObserver(contents); |
| 226 if (!rph_info->second->HasWebContentsObservers()) |
| 227 OnRenderProcessHostDestroyed(rph); |
| 228 } |
| 229 |
| 190 } // namespace | 230 } // namespace |
| 191 | 231 |
| 192 MediaFileSystemInfo::MediaFileSystemInfo(const base::string16& fs_name, | 232 MediaFileSystemInfo::MediaFileSystemInfo(const base::string16& fs_name, |
| 193 const base::FilePath& fs_path, | 233 const base::FilePath& fs_path, |
| 194 const std::string& filesystem_id, | 234 const std::string& filesystem_id, |
| 195 MediaGalleryPrefId pref_id, | 235 MediaGalleryPrefId pref_id, |
| 196 const std::string& transient_device_id, | 236 const std::string& transient_device_id, |
| 197 bool removable, | 237 bool removable, |
| 198 bool media_device) | 238 bool media_device) |
| 199 : name(fs_name), | 239 : name(fs_name), |
| (...skipping 483 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 683 DCHECK_EQ(1U, erase_count); | 723 DCHECK_EQ(1U, erase_count); |
| 684 if (extension_hosts->second.empty()) { | 724 if (extension_hosts->second.empty()) { |
| 685 // When a profile has no ExtensionGalleriesHosts left, remove the | 725 // When a profile has no ExtensionGalleriesHosts left, remove the |
| 686 // matching gallery-change-watcher since it is no longer needed. Leave the | 726 // matching gallery-change-watcher since it is no longer needed. Leave the |
| 687 // |extension_hosts| entry alone, since it indicates the profile has been | 727 // |extension_hosts| entry alone, since it indicates the profile has been |
| 688 // previously used. | 728 // previously used. |
| 689 MediaGalleriesPreferences* preferences = GetPreferences(profile); | 729 MediaGalleriesPreferences* preferences = GetPreferences(profile); |
| 690 preferences->RemoveGalleryChangeObserver(this); | 730 preferences->RemoveGalleryChangeObserver(this); |
| 691 } | 731 } |
| 692 } | 732 } |
| OLD | NEW |