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

Side by Side Diff: content/browser/plugin_service.cc

Issue 7387010: Add PluginServiceFilter interface. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebase Created 9 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 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 #include "content/browser/plugin_service.h" 5 #include "content/browser/plugin_service.h"
6 6
7 #include <vector> 7 #include <vector>
8 8
9 #include "base/command_line.h" 9 #include "base/command_line.h"
10 #include "base/compiler_specific.h" 10 #include "base/compiler_specific.h"
11 #include "base/file_path.h"
11 #include "base/path_service.h" 12 #include "base/path_service.h"
12 #include "base/string_util.h" 13 #include "base/string_util.h"
13 #include "base/synchronization/waitable_event.h" 14 #include "base/synchronization/waitable_event.h"
14 #include "base/threading/thread.h" 15 #include "base/threading/thread.h"
15 #include "base/utf_string_conversions.h" 16 #include "base/utf_string_conversions.h"
16 #include "base/values.h" 17 #include "base/values.h"
17 #include "content/browser/browser_thread.h" 18 #include "content/browser/browser_thread.h"
18 #include "content/browser/content_browser_client.h" 19 #include "content/browser/content_browser_client.h"
20 #include "content/browser/plugin_service_filter.h"
19 #include "content/browser/ppapi_plugin_process_host.h" 21 #include "content/browser/ppapi_plugin_process_host.h"
20 #include "content/browser/renderer_host/render_process_host.h" 22 #include "content/browser/renderer_host/render_process_host.h"
21 #include "content/browser/renderer_host/render_view_host.h" 23 #include "content/browser/renderer_host/render_view_host.h"
22 #include "content/browser/resource_context.h" 24 #include "content/browser/resource_context.h"
23 #include "content/common/content_notification_types.h" 25 #include "content/common/content_notification_types.h"
24 #include "content/common/content_switches.h" 26 #include "content/common/content_switches.h"
25 #include "content/common/notification_service.h" 27 #include "content/common/notification_service.h"
26 #include "content/common/pepper_plugin_registry.h" 28 #include "content/common/pepper_plugin_registry.h"
27 #include "content/common/plugin_messages.h" 29 #include "content/common/plugin_messages.h"
28 #include "content/common/view_messages.h" 30 #include "content/common/view_messages.h"
29 #include "webkit/plugins/npapi/plugin_constants_win.h" 31 #include "webkit/plugins/npapi/plugin_constants_win.h"
30 #include "webkit/plugins/npapi/plugin_list.h" 32 #include "webkit/plugins/npapi/plugin_list.h"
31 #include "webkit/plugins/npapi/webplugininfo.h" 33 #include "webkit/plugins/npapi/webplugininfo.h"
32 34
33 #if defined(OS_POSIX) && !defined(OS_MACOSX) 35 #if defined(OS_POSIX) && !defined(OS_MACOSX)
34 using ::base::files::FilePathWatcher; 36 using ::base::files::FilePathWatcher;
35 #endif 37 #endif
36 38
39 using content::PluginServiceFilter;
40
37 #if defined(OS_MACOSX) 41 #if defined(OS_MACOSX)
38 static void NotifyPluginsOfActivation() { 42 static void NotifyPluginsOfActivation() {
39 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 43 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
40 44
41 for (BrowserChildProcessHost::Iterator iter(ChildProcessInfo::PLUGIN_PROCESS); 45 for (BrowserChildProcessHost::Iterator iter(ChildProcessInfo::PLUGIN_PROCESS);
42 !iter.Done(); ++iter) { 46 !iter.Done(); ++iter) {
43 PluginProcessHost* plugin = static_cast<PluginProcessHost*>(*iter); 47 PluginProcessHost* plugin = static_cast<PluginProcessHost*>(*iter);
44 plugin->OnAppActivation(); 48 plugin->OnAppActivation();
45 } 49 }
46 } 50 }
(...skipping 13 matching lines...) Expand all
60 }; 64 };
61 #endif 65 #endif
62 66
63 // static 67 // static
64 PluginService* PluginService::GetInstance() { 68 PluginService* PluginService::GetInstance() {
65 return Singleton<PluginService>::get(); 69 return Singleton<PluginService>::get();
66 } 70 }
67 71
68 PluginService::PluginService() 72 PluginService::PluginService()
69 : ui_locale_( 73 : ui_locale_(
70 content::GetContentClient()->browser()->GetApplicationLocale()) { 74 content::GetContentClient()->browser()->GetApplicationLocale()),
75 filter_(NULL) {
71 RegisterPepperPlugins(); 76 RegisterPepperPlugins();
72 77
73 // Load any specified on the command line as well. 78 // Load any specified on the command line as well.
74 const CommandLine* command_line = CommandLine::ForCurrentProcess(); 79 const CommandLine* command_line = CommandLine::ForCurrentProcess();
75 FilePath path = command_line->GetSwitchValuePath(switches::kLoadPlugin); 80 FilePath path = command_line->GetSwitchValuePath(switches::kLoadPlugin);
76 if (!path.empty()) 81 if (!path.empty())
77 webkit::npapi::PluginList::Singleton()->AddExtraPluginPath(path); 82 webkit::npapi::PluginList::Singleton()->AddExtraPluginPath(path);
78 path = command_line->GetSwitchValuePath(switches::kExtraPluginDir); 83 path = command_line->GetSwitchValuePath(switches::kExtraPluginDir);
79 if (!path.empty()) 84 if (!path.empty())
80 webkit::npapi::PluginList::Singleton()->AddExtraPluginDir(path); 85 webkit::npapi::PluginList::Singleton()->AddExtraPluginDir(path);
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
127 FilePathWatcher* watcher = new FilePathWatcher(); 132 FilePathWatcher* watcher = new FilePathWatcher();
128 VLOG(1) << "Watching for changes in: " << plugin_dirs[i].value(); 133 VLOG(1) << "Watching for changes in: " << plugin_dirs[i].value();
129 BrowserThread::PostTask( 134 BrowserThread::PostTask(
130 BrowserThread::FILE, FROM_HERE, 135 BrowserThread::FILE, FROM_HERE,
131 NewRunnableFunction( 136 NewRunnableFunction(
132 &PluginService::RegisterFilePathWatcher, 137 &PluginService::RegisterFilePathWatcher,
133 watcher, plugin_dirs[i], file_watcher_delegate_)); 138 watcher, plugin_dirs[i], file_watcher_delegate_));
134 file_watchers_.push_back(watcher); 139 file_watchers_.push_back(watcher);
135 } 140 }
136 #endif 141 #endif
137 registrar_.Add(this, content::NOTIFICATION_PLUGIN_ENABLE_STATUS_CHANGED,
138 NotificationService::AllSources());
139 registrar_.Add(this,
140 content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
141 NotificationService::AllSources());
142 } 142 }
143 143
144 PluginService::~PluginService() { 144 PluginService::~PluginService() {
145 #if defined(OS_WIN) 145 #if defined(OS_WIN)
146 // Release the events since they're owned by RegKey, not WaitableEvent. 146 // Release the events since they're owned by RegKey, not WaitableEvent.
147 hkcu_watcher_.StopWatching(); 147 hkcu_watcher_.StopWatching();
148 hklm_watcher_.StopWatching(); 148 hklm_watcher_.StopWatching();
149 if (hkcu_event_.get()) 149 if (hkcu_event_.get())
150 hkcu_event_->Release(); 150 hkcu_event_->Release();
151 if (hklm_event_.get()) 151 if (hklm_event_.get())
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after
273 NOTREACHED(); // Init is not expected to fail. 273 NOTREACHED(); // Init is not expected to fail.
274 return NULL; 274 return NULL;
275 } 275 }
276 return new_host.release(); 276 return new_host.release();
277 } 277 }
278 278
279 void PluginService::OpenChannelToNpapiPlugin( 279 void PluginService::OpenChannelToNpapiPlugin(
280 int render_process_id, 280 int render_process_id,
281 int render_view_id, 281 int render_view_id,
282 const GURL& url, 282 const GURL& url,
283 const GURL& page_url,
283 const std::string& mime_type, 284 const std::string& mime_type,
284 PluginProcessHost::Client* client) { 285 PluginProcessHost::Client* client) {
285 // The PluginList::GetPluginInfo may need to load the plugins. Don't do it on 286 // The PluginList::GetPluginInfo may need to load the plugins. Don't do it on
286 // the IO thread. 287 // the IO thread.
287 BrowserThread::PostTask( 288 BrowserThread::PostTask(
288 BrowserThread::FILE, FROM_HERE, 289 BrowserThread::FILE, FROM_HERE,
289 NewRunnableMethod( 290 NewRunnableMethod(
290 this, &PluginService::GetAllowedPluginForOpenChannelToPlugin, 291 this, &PluginService::GetAllowedPluginForOpenChannelToPlugin,
291 render_process_id, render_view_id, url, mime_type, client)); 292 render_process_id, render_view_id, url, page_url, mime_type,
293 client));
292 } 294 }
293 295
294 void PluginService::OpenChannelToPpapiPlugin( 296 void PluginService::OpenChannelToPpapiPlugin(
295 const FilePath& path, 297 const FilePath& path,
296 PpapiPluginProcessHost::Client* client) { 298 PpapiPluginProcessHost::Client* client) {
297 PpapiPluginProcessHost* plugin_host = FindOrStartPpapiPluginProcess( 299 PpapiPluginProcessHost* plugin_host = FindOrStartPpapiPluginProcess(
298 path, client); 300 path, client);
299 if (plugin_host) 301 if (plugin_host)
300 plugin_host->OpenChannelToPlugin(client); 302 plugin_host->OpenChannelToPlugin(client);
301 else // Send error. 303 else // Send error.
302 client->OnChannelOpened(base::kNullProcessHandle, IPC::ChannelHandle()); 304 client->OnChannelOpened(base::kNullProcessHandle, IPC::ChannelHandle());
303 } 305 }
304 306
305 void PluginService::OpenChannelToPpapiBroker( 307 void PluginService::OpenChannelToPpapiBroker(
306 const FilePath& path, 308 const FilePath& path,
307 PpapiBrokerProcessHost::Client* client) { 309 PpapiBrokerProcessHost::Client* client) {
308 PpapiBrokerProcessHost* plugin_host = FindOrStartPpapiBrokerProcess(path); 310 PpapiBrokerProcessHost* plugin_host = FindOrStartPpapiBrokerProcess(path);
309 if (plugin_host) 311 if (plugin_host)
310 plugin_host->OpenChannelToPpapiBroker(client); 312 plugin_host->OpenChannelToPpapiBroker(client);
311 else // Send error. 313 else // Send error.
312 client->OnChannelOpened(base::kNullProcessHandle, IPC::ChannelHandle()); 314 client->OnChannelOpened(base::kNullProcessHandle, IPC::ChannelHandle());
313 } 315 }
314 316
315 void PluginService::GetAllowedPluginForOpenChannelToPlugin( 317 void PluginService::GetAllowedPluginForOpenChannelToPlugin(
316 int render_process_id, 318 int render_process_id,
317 int render_view_id, 319 int render_view_id,
318 const GURL& url, 320 const GURL& url,
321 const GURL& page_url,
319 const std::string& mime_type, 322 const std::string& mime_type,
320 PluginProcessHost::Client* client) { 323 PluginProcessHost::Client* client) {
321 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 324 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
322 webkit::npapi::WebPluginInfo info; 325 webkit::npapi::WebPluginInfo info;
326 bool allow_wildcard = true;
323 bool found = GetPluginInfo( 327 bool found = GetPluginInfo(
324 render_process_id, render_view_id, url, mime_type, &info, NULL); 328 render_process_id, render_view_id, client->GetResourceContext(),
329 url, page_url, mime_type, allow_wildcard,
330 NULL, &info, NULL);
325 FilePath plugin_path; 331 FilePath plugin_path;
326 if (found) 332 if (found)
327 plugin_path = FilePath(info.path); 333 plugin_path = info.path;
328 334
329 // Now we jump back to the IO thread to finish opening the channel. 335 // Now we jump back to the IO thread to finish opening the channel.
330 BrowserThread::PostTask( 336 BrowserThread::PostTask(
331 BrowserThread::IO, FROM_HERE, 337 BrowserThread::IO, FROM_HERE,
332 NewRunnableMethod( 338 NewRunnableMethod(
333 this, &PluginService::FinishOpenChannelToPlugin, 339 this, &PluginService::FinishOpenChannelToPlugin,
334 plugin_path, client)); 340 plugin_path, client));
335 } 341 }
336 342
337 void PluginService::FinishOpenChannelToPlugin( 343 void PluginService::FinishOpenChannelToPlugin(
338 const FilePath& plugin_path, 344 const FilePath& plugin_path,
339 PluginProcessHost::Client* client) { 345 PluginProcessHost::Client* client) {
340 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 346 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
341 347
342 PluginProcessHost* plugin_host = FindOrStartNpapiPluginProcess(plugin_path); 348 PluginProcessHost* plugin_host = FindOrStartNpapiPluginProcess(plugin_path);
343 if (plugin_host) 349 if (plugin_host)
344 plugin_host->OpenChannelToPlugin(client); 350 plugin_host->OpenChannelToPlugin(client);
345 else 351 else
346 client->OnError(); 352 client->OnError();
347 } 353 }
348 354
349 bool PluginService::GetPluginInfo(int render_process_id, 355 bool PluginService::GetPluginInfo(int render_process_id,
350 int render_view_id, 356 int render_view_id,
357 const content::ResourceContext& context,
351 const GURL& url, 358 const GURL& url,
359 const GURL& page_url,
352 const std::string& mime_type, 360 const std::string& mime_type,
361 bool allow_wildcard,
362 bool* use_stale,
353 webkit::npapi::WebPluginInfo* info, 363 webkit::npapi::WebPluginInfo* info,
354 std::string* actual_mime_type) { 364 std::string* actual_mime_type) {
365 webkit::npapi::PluginList* plugin_list =
366 webkit::npapi::PluginList::Singleton();
355 // GetPluginInfoArray may need to load the plugins, so we need to be 367 // GetPluginInfoArray may need to load the plugins, so we need to be
356 // on the FILE thread. 368 // on the FILE thread.
357 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 369 DCHECK(use_stale || BrowserThread::CurrentlyOn(BrowserThread::FILE));
358 {
359 base::AutoLock auto_lock(overridden_plugins_lock_);
360 for (size_t i = 0; i < overridden_plugins_.size(); ++i) {
361 if (overridden_plugins_[i].render_process_id == render_process_id &&
362 overridden_plugins_[i].render_view_id == render_view_id &&
363 overridden_plugins_[i].url == url) {
364 if (actual_mime_type)
365 *actual_mime_type = mime_type;
366 *info = overridden_plugins_[i].plugin;
367 return true;
368 }
369 }
370 }
371 bool allow_wildcard = true;
372 std::vector<webkit::npapi::WebPluginInfo> plugins; 370 std::vector<webkit::npapi::WebPluginInfo> plugins;
373 std::vector<std::string> mime_types; 371 std::vector<std::string> mime_types;
374 webkit::npapi::PluginList::Singleton()->GetPluginInfoArray( 372 plugin_list->GetPluginInfoArray(
375 url, mime_type, allow_wildcard, NULL, &plugins, &mime_types); 373 url, mime_type, allow_wildcard, use_stale, &plugins, &mime_types);
374 if (plugins.size() > 1 &&
375 plugins.back().path ==
376 FilePath(webkit::npapi::kDefaultPluginLibraryName)) {
377 // If there is at least one plug-in handling the required MIME type (apart
378 // from the default plug-in), we don't need the default plug-in.
379 plugins.pop_back();
380 }
381
376 for (size_t i = 0; i < plugins.size(); ++i) { 382 for (size_t i = 0; i < plugins.size(); ++i) {
377 if (webkit::npapi::IsPluginEnabled(plugins[i])) { 383 if (!filter_ || filter_->ShouldUsePlugin(render_process_id,
384 render_view_id,
385 context,
386 url,
387 page_url,
388 &plugins[i])) {
378 *info = plugins[i]; 389 *info = plugins[i];
379 if (actual_mime_type) 390 if (actual_mime_type)
380 *actual_mime_type = mime_types[i]; 391 *actual_mime_type = mime_types[i];
381 return true; 392 return true;
382 } 393 }
383 } 394 }
384 return false; 395 return false;
385 } 396 }
386 397
398 void PluginService::GetPlugins(
399 const content::ResourceContext& context,
400 std::vector<webkit::npapi::WebPluginInfo>* plugins) {
401 // GetPlugins may need to load the plugins, so we need to be
402 // on the FILE thread.
403 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
404 webkit::npapi::PluginList* plugin_list =
405 webkit::npapi::PluginList::Singleton();
406 std::vector<webkit::npapi::WebPluginInfo> all_plugins;
407 plugin_list->GetPlugins(&all_plugins);
408
409 int child_process_id = -1;
410 int routing_id = MSG_ROUTING_NONE;
411 for (size_t i = 0; i < all_plugins.size(); ++i) {
412 if (!filter_ || filter_->ShouldUsePlugin(child_process_id,
413 routing_id,
414 context,
415 GURL(),
416 GURL(),
417 &all_plugins[i])) {
418 plugins->push_back(all_plugins[i]);
419 }
420 }
421 }
422
387 void PluginService::OnWaitableEventSignaled( 423 void PluginService::OnWaitableEventSignaled(
388 base::WaitableEvent* waitable_event) { 424 base::WaitableEvent* waitable_event) {
389 #if defined(OS_WIN) 425 #if defined(OS_WIN)
390 if (waitable_event == hkcu_event_.get()) { 426 if (waitable_event == hkcu_event_.get()) {
391 hkcu_key_.StartWatching(); 427 hkcu_key_.StartWatching();
392 } else { 428 } else {
393 hklm_key_.StartWatching(); 429 hklm_key_.StartWatching();
394 } 430 }
395 431
396 webkit::npapi::PluginList::Singleton()->RefreshPlugins(); 432 webkit::npapi::PluginList::Singleton()->RefreshPlugins();
397 PurgePluginListCache(true); 433 PurgePluginListCache(true);
398 #else 434 #else
399 // This event should only get signaled on a Windows machine. 435 // This event should only get signaled on a Windows machine.
400 NOTREACHED(); 436 NOTREACHED();
401 #endif // defined(OS_WIN) 437 #endif // defined(OS_WIN)
402 } 438 }
403 439
404 void PluginService::Observe(int type, 440 void PluginService::Observe(int type,
405 const NotificationSource& source, 441 const NotificationSource& source,
406 const NotificationDetails& details) { 442 const NotificationDetails& details) {
407 switch (type) {
408 #if defined(OS_MACOSX) 443 #if defined(OS_MACOSX)
409 case content::NOTIFICATION_APP_ACTIVATED: { 444 if (type == content::NOTIFICATION_APP_ACTIVATED) {
410 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, 445 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
411 NewRunnableFunction(&NotifyPluginsOfActivation)); 446 NewRunnableFunction(&NotifyPluginsOfActivation));
412 break; 447 return;
413 } 448 }
414 #endif 449 #endif
415 450 NOTREACHED();
416 case content::NOTIFICATION_PLUGIN_ENABLE_STATUS_CHANGED: {
417 webkit::npapi::PluginList::Singleton()->RefreshPlugins();
418 PurgePluginListCache(false);
419 break;
420 }
421 case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: {
422 int render_process_id = Source<RenderProcessHost>(source).ptr()->id();
423
424 base::AutoLock auto_lock(overridden_plugins_lock_);
425 for (size_t i = 0; i < overridden_plugins_.size(); ++i) {
426 if (overridden_plugins_[i].render_process_id == render_process_id) {
427 overridden_plugins_.erase(overridden_plugins_.begin() + i);
428 break;
429 }
430 }
431 break;
432 }
433 default:
434 NOTREACHED();
435 }
436 }
437
438 void PluginService::OverridePluginForTab(const OverriddenPlugin& plugin) {
439 base::AutoLock auto_lock(overridden_plugins_lock_);
440 overridden_plugins_.push_back(plugin);
441 } 451 }
442 452
443 void PluginService::PurgePluginListCache(bool reload_pages) { 453 void PluginService::PurgePluginListCache(bool reload_pages) {
444 for (RenderProcessHost::iterator it = RenderProcessHost::AllHostsIterator(); 454 for (RenderProcessHost::iterator it = RenderProcessHost::AllHostsIterator();
445 !it.IsAtEnd(); it.Advance()) { 455 !it.IsAtEnd(); it.Advance()) {
446 it.GetCurrentValue()->Send(new ViewMsg_PurgePluginListCache(reload_pages)); 456 it.GetCurrentValue()->Send(new ViewMsg_PurgePluginListCache(reload_pages));
447 } 457 }
448 } 458 }
449 459
450 void PluginService::RestrictPluginToUrl(const FilePath& plugin_path,
451 const GURL& url) {
452 base::AutoLock auto_lock(restricted_plugin_lock_);
453 if (url.is_empty()) {
454 restricted_plugin_.erase(plugin_path);
455 } else {
456 restricted_plugin_[plugin_path] = url;
457 }
458 }
459
460 bool PluginService::PluginAllowedForURL(const FilePath& plugin_path,
461 const GURL& url) {
462 if (url.is_empty())
463 return true; // Caller wants all plugins.
464
465 base::AutoLock auto_lock(restricted_plugin_lock_);
466
467 RestrictedPluginMap::iterator it = restricted_plugin_.find(plugin_path);
468 if (it == restricted_plugin_.end())
469 return true; // This plugin is not restricted, so it's allowed everywhere.
470
471 const GURL& required_url = it->second;
472 return (url.scheme() == required_url.scheme() &&
473 url.host() == required_url.host());
474 }
475
476 void PluginService::RegisterPepperPlugins() { 460 void PluginService::RegisterPepperPlugins() {
477 // TODO(abarth): It seems like the PepperPluginRegistry should do this work. 461 // TODO(abarth): It seems like the PepperPluginRegistry should do this work.
478 PepperPluginRegistry::ComputeList(&ppapi_plugins_); 462 PepperPluginRegistry::ComputeList(&ppapi_plugins_);
479 for (size_t i = 0; i < ppapi_plugins_.size(); ++i) { 463 for (size_t i = 0; i < ppapi_plugins_.size(); ++i) {
480 webkit::npapi::PluginList::Singleton()->RegisterInternalPlugin( 464 webkit::npapi::PluginList::Singleton()->RegisterInternalPlugin(
481 ppapi_plugins_[i].ToWebPluginInfo()); 465 ppapi_plugins_[i].ToWebPluginInfo());
482 } 466 }
483 } 467 }
484 468
485 // There should generally be very few plugins so a brute-force search is fine. 469 // There should generally be very few plugins so a brute-force search is fine.
(...skipping 12 matching lines...) Expand all
498 #if defined(OS_POSIX) && !defined(OS_MACOSX) 482 #if defined(OS_POSIX) && !defined(OS_MACOSX)
499 // static 483 // static
500 void PluginService::RegisterFilePathWatcher( 484 void PluginService::RegisterFilePathWatcher(
501 FilePathWatcher *watcher, 485 FilePathWatcher *watcher,
502 const FilePath& path, 486 const FilePath& path,
503 FilePathWatcher::Delegate* delegate) { 487 FilePathWatcher::Delegate* delegate) {
504 bool result = watcher->Watch(path, delegate); 488 bool result = watcher->Watch(path, delegate);
505 DCHECK(result); 489 DCHECK(result);
506 } 490 }
507 #endif 491 #endif
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698