OLD | NEW |
---|---|
(Empty) | |
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 | |
3 // found in the LICENSE file. | |
4 // | |
5 // GalleryWatchManager implementation. | |
6 | |
7 #include "chrome/browser/extensions/api/media_galleries_private/gallery_watch_ma nager.h" | |
8 | |
9 #include <list> | |
10 #include <set> | |
11 | |
12 #include "base/bind.h" | |
13 #include "base/compiler_specific.h" | |
14 #include "base/files/file_path_watcher.h" | |
15 #include "base/location.h" | |
16 #include "base/memory/weak_ptr.h" | |
17 #include "base/time.h" | |
18 #include "chrome/browser/extensions/api/media_galleries_private/media_galleries_ private_api.h" | |
19 #include "chrome/browser/extensions/api/media_galleries_private/media_galleries_ private_api_factory.h" | |
20 #include "chrome/browser/extensions/api/media_galleries_private/media_galleries_ private_event_router.h" | |
21 #include "chrome/browser/profiles/profile.h" | |
22 #include "content/public/browser/browser_thread.h" | |
23 | |
24 namespace extensions { | |
25 | |
26 class GalleryWatchManager; | |
27 | |
28 namespace { | |
29 | |
30 using content::BrowserThread; | |
31 | |
32 // Map to keep track of profile specific GalleryWatchManager objects. | |
33 // Key: Profile*. | |
34 // Value: GalleryWatchManager*. | |
35 // This map owns the GalleryWatchManager object. | |
36 typedef std::map<const Profile*, extensions::GalleryWatchManager*> | |
37 WatchManagerMap; | |
38 WatchManagerMap* g_gallery_watch_managers = NULL; | |
39 | |
40 // Dispatches the gallery changed event on the UI thread. | |
41 void SendGalleryChangedEventOnUIThread( | |
42 const Profile* profile, | |
43 const std::string& gallery_id, | |
44 const std::set<std::string>& extension_ids) { | |
45 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
46 DCHECK(profile); | |
47 MediaGalleriesPrivateEventRouter* router = | |
48 MediaGalleriesPrivateAPIFactory::GetForProfile( | |
49 const_cast<Profile*>(profile))->event_router(); | |
Lei Zhang
2012/12/18 01:45:16
GalleryWatchManager shouldn't promise to use a con
kmadhusu
2012/12/18 21:32:39
Done.
| |
50 if (!router) | |
51 return; | |
52 router->OnGalleryChanged(gallery_id, extension_ids); | |
53 } | |
54 | |
55 } // namespace | |
56 | |
57 /////////////////////////////////////////////////////////////////////////////// | |
58 // GalleryFilePathWatcher // | |
59 /////////////////////////////////////////////////////////////////////////////// | |
60 | |
61 // Gallery file path watcher delegate to handle the gallery change | |
Lei Zhang
2012/12/18 01:45:16
From this comment, I still have trouble understand
kmadhusu
2012/12/18 21:32:39
How about this?
// This class does a recursive wat
Lei Zhang
2012/12/19 01:03:47
Your comment still does not answer the question of
kmadhusu
2012/12/19 21:55:55
sure. Done.
| |
62 // notifications. This class manages all the extension usage and forwards | |
63 // the gallery change notifications to the extensions. This class lives on | |
64 // the FILE thread. This class is instantiated per gallery watch path and does | |
65 // recursive watches. | |
66 class GalleryFilePathWatcher : public base::RefCounted<GalleryFilePathWatcher> { | |
67 public: | |
68 GalleryFilePathWatcher(const Profile* profile, | |
69 const std::string& gallery_id, | |
70 const FilePath& path, | |
71 const std::string& extension_id); | |
72 | |
73 // Adds the extension specified by the |extension_id| to the | |
74 // ExtensionWatchInfoMap and initiate the watch operation. | |
Lei Zhang
2012/12/18 01:45:16
What does "initiate the watch operation" mean? How
kmadhusu
2012/12/18 21:32:39
This function adds an extension reference to the w
| |
75 void AddExtension(const std::string& extension_id); | |
76 | |
77 // Cancels the watch for the extension specified by the |extension_id|. | |
78 void RemoveExtension(const std::string& extension_id); | |
79 | |
80 // Handles the extension unloaded/uninstalled/destroyed event. | |
81 void OnExtensionDestroyed(const std::string& extension_id); | |
82 | |
83 // Sets up the watch operation for the specified |gallery_path_|. On | |
84 // success, returns true. | |
85 bool SetupWatch(); | |
86 | |
87 // Removes all the extension references when the browser profile is in | |
88 // shutdown mode. | |
89 void RemoveAllWatchReferences(); | |
90 | |
91 private: | |
92 friend class base::RefCounted<GalleryFilePathWatcher>; | |
93 | |
94 // Keeps track of extension watch details. | |
95 struct ExtensionWatchInfo { | |
Lei Zhang
2012/12/18 01:45:16
Are you keeping track of how many times a particul
kmadhusu
2012/12/18 21:32:39
Yes
| |
96 ExtensionWatchInfo(); | |
97 | |
98 // Number of watches in this extension, e.g "3" | |
99 unsigned int watch_count; | |
100 | |
101 // Used to manage the gallery changed events. | |
102 base::Time last_gallery_changed_event; | |
103 }; | |
104 | |
105 typedef std::map<std::string, ExtensionWatchInfo> ExtensionWatchInfoMap; | |
106 | |
107 // Private because GalleryFilePathWatcher is ref-counted. | |
108 virtual ~GalleryFilePathWatcher(); | |
109 | |
110 // FilePathWatcher callback. | |
111 void OnFilePathChanged(const FilePath& path, bool error); | |
112 | |
113 // Remove the watch references for the extension specified by the | |
114 // |extension_id|. | |
115 void RemoveExtensionReferences(const std::string& extension_id); | |
116 | |
117 // Current profile. | |
118 const Profile* profile_; | |
119 | |
120 // The gallery identifier, e.g "1". | |
121 const std::string gallery_id_; | |
122 | |
123 // The gallery file path watcher. | |
124 base::files::FilePathWatcher file_watcher_; | |
125 | |
126 // The gallery file path, e.g "C:\My Pictures". | |
127 FilePath gallery_path_; | |
128 | |
129 // Map to keep track of the extension and its corresponding watch count. | |
130 // Key: Extension identifier, e.g "qoueruoweuroiwueroiwujkshdf". | |
131 // Value: Watch information. | |
132 ExtensionWatchInfoMap extension_watch_info_map_; | |
133 | |
134 // Used to provide a weak pointer to FilePathWatcher callback. | |
135 base::WeakPtrFactory<GalleryFilePathWatcher> weak_ptr_factory_; | |
136 | |
137 DISALLOW_COPY_AND_ASSIGN(GalleryFilePathWatcher); | |
138 }; | |
139 | |
140 GalleryFilePathWatcher::GalleryFilePathWatcher(const Profile* profile, | |
141 const std::string& gallery_id, | |
142 const FilePath& path, | |
143 const std::string& extension_id) | |
144 : profile_(profile), | |
145 gallery_id_(gallery_id), | |
146 weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { | |
147 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
148 gallery_path_ = path; | |
149 AddExtension(extension_id); | |
150 } | |
151 | |
152 void GalleryFilePathWatcher::AddExtension(const std::string& extension_id) { | |
153 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
154 ExtensionWatchInfoMap::iterator it = | |
155 extension_watch_info_map_.find(extension_id); | |
156 if (it != extension_watch_info_map_.end()) { | |
157 it->second.watch_count++; | |
158 } else { | |
159 extension_watch_info_map_.insert( | |
160 ExtensionWatchInfoMap::value_type(extension_id, ExtensionWatchInfo())); | |
161 } | |
162 AddRef(); | |
163 } | |
164 | |
165 void GalleryFilePathWatcher::RemoveExtension(const std::string& extension_id) { | |
166 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
167 ExtensionWatchInfoMap::iterator it = | |
168 extension_watch_info_map_.find(extension_id); | |
169 if (it == extension_watch_info_map_.end()) | |
170 return; | |
171 // If entry found - decrease it's count and remove if necessary | |
172 it->second.watch_count--; | |
173 if (0 == it->second.watch_count) | |
174 extension_watch_info_map_.erase(it); | |
175 Release(); | |
176 } | |
177 | |
178 void GalleryFilePathWatcher::OnExtensionDestroyed( | |
179 const std::string& extension_id) { | |
180 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
181 RemoveExtensionReferences(extension_id); | |
182 } | |
183 | |
184 bool GalleryFilePathWatcher::SetupWatch() { | |
185 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
186 return file_watcher_.Watch( | |
187 gallery_path_, true, | |
188 base::Bind(&GalleryFilePathWatcher::OnFilePathChanged, | |
189 weak_ptr_factory_.GetWeakPtr())); | |
190 } | |
191 | |
192 void GalleryFilePathWatcher::RemoveAllWatchReferences() { | |
193 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
194 std::set<std::string> extension_ids; | |
195 for (ExtensionWatchInfoMap::iterator iter = extension_watch_info_map_.begin(); | |
196 iter != extension_watch_info_map_.end(); ++iter) | |
197 extension_ids.insert(iter->first); | |
198 | |
199 for (std::set<std::string>::const_iterator it = extension_ids.begin(); | |
200 it != extension_ids.end(); ++it) | |
201 RemoveExtensionReferences(*it); | |
202 } | |
203 | |
204 GalleryFilePathWatcher::~GalleryFilePathWatcher() { | |
205 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
206 } | |
207 | |
208 GalleryFilePathWatcher::ExtensionWatchInfo::ExtensionWatchInfo() | |
209 : watch_count(1) { | |
210 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
Lei Zhang
2012/12/18 01:45:16
Structs should not do anything other can carry val
kmadhusu
2012/12/18 21:32:39
Done.
| |
211 } | |
212 | |
213 void GalleryFilePathWatcher::OnFilePathChanged(const FilePath& path, | |
214 bool error) { | |
215 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
216 if (error || (path != gallery_path_)) | |
217 return; | |
218 | |
219 std::set<std::string> extension_ids; | |
220 for (ExtensionWatchInfoMap::iterator iter = extension_watch_info_map_.begin(); | |
221 iter != extension_watch_info_map_.end(); ++iter) { | |
222 if (!iter->second.last_gallery_changed_event.is_null()) { | |
223 // Ignore gallery change event if it is received too frequently. | |
224 // For example, when an user copies/deletes 1000 media files from a | |
225 // gallery, this callback is called 1000 times within a span of 10ms. | |
226 // GalleryWatchManager should not send 1000 gallery changed events to | |
227 // the watching extension. | |
228 const int kMinSecondsToIgnoreGalleryChangedEvent = 3; | |
229 base::TimeDelta diff = | |
230 base::Time::Now() - iter->second.last_gallery_changed_event; | |
231 if (diff.InSeconds() < kMinSecondsToIgnoreGalleryChangedEvent) | |
232 continue; | |
233 } | |
234 iter->second.last_gallery_changed_event = base::Time::Now(); | |
235 extension_ids.insert(iter->first); | |
236 } | |
237 if (!extension_ids.empty()) { | |
238 content::BrowserThread::PostTask( | |
239 content::BrowserThread::UI, FROM_HERE, | |
240 base::Bind(SendGalleryChangedEventOnUIThread, profile_, gallery_id_, | |
241 extension_ids)); | |
242 } | |
243 } | |
244 | |
245 void GalleryFilePathWatcher::RemoveExtensionReferences( | |
246 const std::string& extension_id) { | |
247 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
248 ExtensionWatchInfoMap::iterator it = | |
249 extension_watch_info_map_.find(extension_id); | |
250 if (it == extension_watch_info_map_.end()) | |
251 return; | |
252 const ExtensionWatchInfo watch_info = it->second; | |
253 for (unsigned int i = 0; i < watch_info.watch_count; ++i) | |
254 Release(); | |
255 extension_watch_info_map_.erase(it); | |
256 } | |
257 | |
258 /////////////////////////////////////////////////////////////////////////////// | |
259 // GalleryWatchManager // | |
260 /////////////////////////////////////////////////////////////////////////////// | |
261 | |
262 // static | |
263 GalleryWatchManager* GalleryWatchManager::GetForProfile( | |
264 const Profile* profile) { | |
265 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
266 DCHECK(profile); | |
267 bool has_watch_manager = (g_gallery_watch_managers && | |
268 GalleryWatchManager::HasForProfile(profile)); | |
269 if (!g_gallery_watch_managers) | |
270 g_gallery_watch_managers = new WatchManagerMap; | |
271 if (!has_watch_manager) | |
272 (*g_gallery_watch_managers)[profile] = new GalleryWatchManager(profile); | |
273 return (*g_gallery_watch_managers)[profile]; | |
274 } | |
275 | |
276 // static | |
277 bool GalleryWatchManager::HasForProfile(const Profile* profile) { | |
278 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
279 DCHECK(profile); | |
280 if (!g_gallery_watch_managers) | |
281 return false; | |
282 WatchManagerMap::const_iterator it = g_gallery_watch_managers->find(profile); | |
283 return (it != g_gallery_watch_managers->end()); | |
284 } | |
285 | |
286 // static | |
287 void GalleryWatchManager::OnProfileShutdown(const Profile* profile) { | |
288 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
289 DCHECK(profile); | |
290 if (!g_gallery_watch_managers || g_gallery_watch_managers->empty()) | |
291 return; | |
292 WatchManagerMap::iterator it = g_gallery_watch_managers->find(profile); | |
293 if (it == g_gallery_watch_managers->end()) | |
294 return; | |
295 delete it->second; | |
296 g_gallery_watch_managers->erase(it); | |
297 if (g_gallery_watch_managers->empty()) | |
298 delete g_gallery_watch_managers; | |
299 } | |
300 | |
301 GalleryWatchManager::~GalleryWatchManager() { | |
302 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
303 if (!gallery_watchers_.empty()) { | |
304 // User closed the extension/browser without stoping the gallery watchers. | |
305 DeleteAllWatchers(); | |
306 } | |
307 DCHECK(gallery_watchers_.empty()); | |
308 } | |
309 | |
310 bool GalleryWatchManager::StartGalleryWatch( | |
311 const std::string& gallery_id, | |
312 const FilePath& watch_path, | |
313 const std::string& extension_id) { | |
314 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
315 WatcherMap::const_iterator iter = gallery_watchers_.find(watch_path); | |
316 if (iter != gallery_watchers_.end()) { | |
317 // Already watched. | |
318 iter->second->AddExtension(extension_id); | |
319 return true; | |
320 } | |
321 | |
322 // Need to add a new watcher. | |
323 scoped_refptr<GalleryFilePathWatcher> watch( | |
324 new GalleryFilePathWatcher(profile_, gallery_id, watch_path, | |
325 extension_id)); | |
326 if (!watch->SetupWatch()) | |
327 return false; | |
328 gallery_watchers_[watch_path] = watch; | |
329 return true; | |
330 } | |
331 | |
332 void GalleryWatchManager::StopGalleryWatch( | |
333 const FilePath& watch_path, | |
334 const std::string& extension_id) { | |
335 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
336 WatcherMap::iterator iter = gallery_watchers_.find(watch_path); | |
337 if (iter == gallery_watchers_.end()) | |
338 return; | |
339 // Remove the renderer process for this watch. | |
340 iter->second->RemoveExtension(extension_id); | |
341 if (iter->second->HasOneRef()) { | |
342 // There are no references other than the one |gallery_watchers_| holds. | |
343 iter->second = NULL; | |
344 gallery_watchers_.erase(iter); | |
345 } | |
346 } | |
347 | |
348 void GalleryWatchManager::OnExtensionDestroyed( | |
349 const std::string& extension_id) { | |
350 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
351 std::list<FilePath> watchers_to_erase; | |
352 for (WatcherMap::iterator iter = gallery_watchers_.begin(); | |
353 iter != gallery_watchers_.end(); ++iter) { | |
354 // Remove the renderer process for this watch. | |
355 iter->second->OnExtensionDestroyed(extension_id); | |
356 if (iter->second->HasOneRef()) { | |
357 // There are no references other than the one |gallery_watchers_| holds. | |
358 watchers_to_erase.push_back(iter->first); | |
359 } | |
360 } | |
361 | |
362 for (std::list<FilePath>::const_iterator path = watchers_to_erase.begin(); | |
363 path != watchers_to_erase.end(); ++path) { | |
364 WatcherMap::iterator iter = gallery_watchers_.find(*path); | |
365 DCHECK(iter != gallery_watchers_.end()); | |
366 iter->second = NULL; | |
367 gallery_watchers_.erase(iter); | |
368 } | |
369 } | |
370 | |
371 GalleryWatchManager::GalleryWatchManager(const Profile* profile) | |
372 : profile_(profile) { | |
373 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
374 } | |
375 | |
376 void GalleryWatchManager::DeleteAllWatchers() { | |
377 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
378 std::list<FilePath> watchers_to_erase; | |
379 for (WatcherMap::iterator iter = gallery_watchers_.begin(); | |
380 iter != gallery_watchers_.end(); ++iter) { | |
381 iter->second->RemoveAllWatchReferences(); | |
382 // Verify that there are no references other than the one | |
383 // |gallery_watchers_| holds. | |
384 DCHECK(iter->second->HasOneRef()); | |
385 watchers_to_erase.push_back(iter->first); | |
386 } | |
387 | |
388 for (std::list<FilePath>::const_iterator path = watchers_to_erase.begin(); | |
389 path != watchers_to_erase.end(); ++path) { | |
390 WatcherMap::iterator iter = gallery_watchers_.find(*path); | |
391 DCHECK(iter != gallery_watchers_.end()); | |
392 iter->second = NULL; | |
393 gallery_watchers_.erase(iter); | |
394 } | |
395 } | |
396 | |
397 } // namespace extensions | |
OLD | NEW |