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

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

Issue 7980011: Convert the PluginService interface to be an async wrapper around PluginList. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Ready for review Created 9 years, 3 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 "base/bind.h"
7 #include "base/command_line.h" 8 #include "base/command_line.h"
8 #include "base/compiler_specific.h" 9 #include "base/compiler_specific.h"
9 #include "base/file_path.h" 10 #include "base/file_path.h"
11 #include "base/message_loop.h"
12 #include "base/message_loop_proxy.h"
10 #include "base/path_service.h" 13 #include "base/path_service.h"
11 #include "base/string_util.h" 14 #include "base/string_util.h"
12 #include "base/synchronization/waitable_event.h" 15 #include "base/synchronization/waitable_event.h"
13 #include "base/threading/thread.h" 16 #include "base/threading/thread.h"
14 #include "base/utf_string_conversions.h" 17 #include "base/utf_string_conversions.h"
15 #include "base/values.h" 18 #include "base/values.h"
16 #include "content/browser/browser_thread.h" 19 #include "content/browser/browser_thread.h"
17 #include "content/browser/content_browser_client.h" 20 #include "content/browser/content_browser_client.h"
18 #include "content/browser/plugin_service_filter.h" 21 #include "content/browser/plugin_service_filter.h"
19 #include "content/browser/ppapi_plugin_process_host.h" 22 #include "content/browser/ppapi_plugin_process_host.h"
20 #include "content/browser/renderer_host/render_process_host.h" 23 #include "content/browser/renderer_host/render_process_host.h"
21 #include "content/browser/renderer_host/render_view_host.h" 24 #include "content/browser/renderer_host/render_view_host.h"
22 #include "content/browser/resource_context.h" 25 #include "content/browser/resource_context.h"
23 #include "content/common/content_notification_types.h" 26 #include "content/common/content_notification_types.h"
24 #include "content/common/content_switches.h" 27 #include "content/common/content_switches.h"
25 #include "content/common/notification_service.h" 28 #include "content/common/notification_service.h"
26 #include "content/common/pepper_plugin_registry.h" 29 #include "content/common/pepper_plugin_registry.h"
27 #include "content/common/plugin_messages.h" 30 #include "content/common/plugin_messages.h"
28 #include "content/common/view_messages.h" 31 #include "content/common/view_messages.h"
32 #include "webkit/plugins/npapi/mock_plugin_list.h"
Bernhard Bauer 2011/09/21 14:31:26 Nit: Should PluginService really know about testin
29 #include "webkit/plugins/npapi/plugin_constants_win.h" 33 #include "webkit/plugins/npapi/plugin_constants_win.h"
30 #include "webkit/plugins/npapi/plugin_list.h" 34 #include "webkit/plugins/npapi/plugin_list.h"
31 #include "webkit/plugins/webplugininfo.h" 35 #include "webkit/plugins/webplugininfo.h"
32 36
33 #if defined(OS_POSIX) && !defined(OS_MACOSX) 37 #if defined(OS_POSIX) && !defined(OS_MACOSX)
34 using ::base::files::FilePathWatcher; 38 using ::base::files::FilePathWatcher;
35 #endif 39 #endif
36 40
37 using content::PluginServiceFilter; 41 using content::PluginServiceFilter;
38 42
43 namespace {
44
45 // Helper function that merely runs the callback with the result. Called on the
46 // thread on which the original GetPlugins() call was made.
47 static void RunGetPluginsCallback(
48 const PluginService::GetPluginsCallback& callback,
49 std::vector<webkit::WebPluginInfo> result) {
50 callback.Run(result);
51 }
52
53 // A callback for GetPlugins() that then gets the freshly loaded plugin groups
54 // and runs the callback for GetPluginGroups().
55 static void GetPluginsForGroupsCallback(
56 const PluginService::GetPluginGroupsCallback& callback,
57 std::vector<webkit::WebPluginInfo> /* unused */) {
jam 2011/09/21 00:04:51 nit: const ref. also, "unused" isn't a convention
Robert Sesek 2011/09/21 01:13:44 As stated in the comments, this is the callback fo
58 std::vector<webkit::npapi::PluginGroup> groups;
59 PluginService::GetInstance()->GetCachedPluginGroups(&groups);
60 callback.Run(groups);
61 }
62
63 } // namespace
64
39 #if defined(OS_MACOSX) 65 #if defined(OS_MACOSX)
40 static void NotifyPluginsOfActivation() { 66 static void NotifyPluginsOfActivation() {
41 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 67 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
42 68
43 for (BrowserChildProcessHost::Iterator iter(ChildProcessInfo::PLUGIN_PROCESS); 69 for (BrowserChildProcessHost::Iterator iter(ChildProcessInfo::PLUGIN_PROCESS);
44 !iter.Done(); ++iter) { 70 !iter.Done(); ++iter) {
45 PluginProcessHost* plugin = static_cast<PluginProcessHost*>(*iter); 71 PluginProcessHost* plugin = static_cast<PluginProcessHost*>(*iter);
46 plugin->OnAppActivation(); 72 plugin->OnAppActivation();
47 } 73 }
48 } 74 }
(...skipping 14 matching lines...) Expand all
63 #endif 89 #endif
64 90
65 // static 91 // static
66 PluginService* PluginService::GetInstance() { 92 PluginService* PluginService::GetInstance() {
67 return Singleton<PluginService>::get(); 93 return Singleton<PluginService>::get();
68 } 94 }
69 95
70 PluginService::PluginService() 96 PluginService::PluginService()
71 : ui_locale_( 97 : ui_locale_(
72 content::GetContentClient()->browser()->GetApplicationLocale()), 98 content::GetContentClient()->browser()->GetApplicationLocale()),
73 filter_(NULL) { 99 filter_(NULL),
100 plugin_list_(NULL) {
74 RegisterPepperPlugins(); 101 RegisterPepperPlugins();
75 102
76 // Load any specified on the command line as well. 103 // Load any specified on the command line as well.
77 const CommandLine* command_line = CommandLine::ForCurrentProcess(); 104 const CommandLine* command_line = CommandLine::ForCurrentProcess();
78 FilePath path = command_line->GetSwitchValuePath(switches::kLoadPlugin); 105 FilePath path = command_line->GetSwitchValuePath(switches::kLoadPlugin);
79 if (!path.empty()) 106 if (!path.empty())
80 webkit::npapi::PluginList::Singleton()->AddExtraPluginPath(path); 107 webkit::npapi::PluginList::Singleton()->AddExtraPluginPath(path);
81 path = command_line->GetSwitchValuePath(switches::kExtraPluginDir); 108 path = command_line->GetSwitchValuePath(switches::kExtraPluginDir);
82 if (!path.empty()) 109 if (!path.empty())
83 webkit::npapi::PluginList::Singleton()->AddExtraPluginDir(path); 110 webkit::npapi::PluginList::Singleton()->AddExtraPluginDir(path);
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
127 } 154 }
128 #elif defined(OS_POSIX) && !defined(OS_MACOSX) 155 #elif defined(OS_POSIX) && !defined(OS_MACOSX)
129 // The FilePathWatcher produces too many false positives on MacOS (access time 156 // The FilePathWatcher produces too many false positives on MacOS (access time
130 // updates?) which will lead to enforcing updates of the plugins way too often. 157 // updates?) which will lead to enforcing updates of the plugins way too often.
131 // On ChromeOS the user can't install plugins anyway and on Windows all 158 // On ChromeOS the user can't install plugins anyway and on Windows all
132 // important plugins register themselves in the registry so no need to do that. 159 // important plugins register themselves in the registry so no need to do that.
133 file_watcher_delegate_ = new PluginDirWatcherDelegate(); 160 file_watcher_delegate_ = new PluginDirWatcherDelegate();
134 // Get the list of all paths for registering the FilePathWatchers 161 // Get the list of all paths for registering the FilePathWatchers
135 // that will track and if needed reload the list of plugins on runtime. 162 // that will track and if needed reload the list of plugins on runtime.
136 std::vector<FilePath> plugin_dirs; 163 std::vector<FilePath> plugin_dirs;
137 webkit::npapi::PluginList::Singleton()->GetPluginDirectories( 164 GetPluginList()->GetPluginDirectories(&plugin_dirs);
138 &plugin_dirs);
139 165
140 for (size_t i = 0; i < plugin_dirs.size(); ++i) { 166 for (size_t i = 0; i < plugin_dirs.size(); ++i) {
141 // FilePathWatcher can not handle non-absolute paths under windows. 167 // FilePathWatcher can not handle non-absolute paths under windows.
142 // We don't watch for file changes in windows now but if this should ever 168 // We don't watch for file changes in windows now but if this should ever
143 // be extended to Windows these lines might save some time of debugging. 169 // be extended to Windows these lines might save some time of debugging.
144 #if defined(OS_WIN) 170 #if defined(OS_WIN)
145 if (!plugin_dirs[i].IsAbsolute()) 171 if (!plugin_dirs[i].IsAbsolute())
146 continue; 172 continue;
147 #endif 173 #endif
148 FilePathWatcher* watcher = new FilePathWatcher(); 174 FilePathWatcher* watcher = new FilePathWatcher();
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
209 235
210 PluginProcessHost* PluginService::FindOrStartNpapiPluginProcess( 236 PluginProcessHost* PluginService::FindOrStartNpapiPluginProcess(
211 const FilePath& plugin_path) { 237 const FilePath& plugin_path) {
212 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 238 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
213 239
214 PluginProcessHost* plugin_host = FindNpapiPluginProcess(plugin_path); 240 PluginProcessHost* plugin_host = FindNpapiPluginProcess(plugin_path);
215 if (plugin_host) 241 if (plugin_host)
216 return plugin_host; 242 return plugin_host;
217 243
218 webkit::WebPluginInfo info; 244 webkit::WebPluginInfo info;
219 if (!webkit::npapi::PluginList::Singleton()->GetPluginInfoByPath( 245 if (!GetPluginList()->GetPluginInfoByPath(plugin_path, &info)) {
220 plugin_path, &info)) {
221 return NULL; 246 return NULL;
222 } 247 }
223 248
224 // This plugin isn't loaded by any plugin process, so create a new process. 249 // This plugin isn't loaded by any plugin process, so create a new process.
225 scoped_ptr<PluginProcessHost> new_host(new PluginProcessHost()); 250 scoped_ptr<PluginProcessHost> new_host(new PluginProcessHost());
226 if (!new_host->Init(info, ui_locale_)) { 251 if (!new_host->Init(info, ui_locale_)) {
227 NOTREACHED(); // Init is not expected to fail. 252 NOTREACHED(); // Init is not expected to fail.
228 return NULL; 253 return NULL;
229 } 254 }
230 return new_host.release(); 255 return new_host.release();
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after
377 bool PluginService::GetPluginInfo(int render_process_id, 402 bool PluginService::GetPluginInfo(int render_process_id,
378 int render_view_id, 403 int render_view_id,
379 const content::ResourceContext& context, 404 const content::ResourceContext& context,
380 const GURL& url, 405 const GURL& url,
381 const GURL& page_url, 406 const GURL& page_url,
382 const std::string& mime_type, 407 const std::string& mime_type,
383 bool allow_wildcard, 408 bool allow_wildcard,
384 bool* use_stale, 409 bool* use_stale,
385 webkit::WebPluginInfo* info, 410 webkit::WebPluginInfo* info,
386 std::string* actual_mime_type) { 411 std::string* actual_mime_type) {
387 webkit::npapi::PluginList* plugin_list = 412 webkit::npapi::PluginList* plugin_list = GetPluginList();
388 webkit::npapi::PluginList::Singleton();
389 // GetPluginInfoArray may need to load the plugins, so we need to be 413 // GetPluginInfoArray may need to load the plugins, so we need to be
390 // on the FILE thread. 414 // on the FILE thread.
391 DCHECK(use_stale || BrowserThread::CurrentlyOn(BrowserThread::FILE)); 415 DCHECK(use_stale || BrowserThread::CurrentlyOn(BrowserThread::FILE));
392 std::vector<webkit::WebPluginInfo> plugins; 416 std::vector<webkit::WebPluginInfo> plugins;
393 std::vector<std::string> mime_types; 417 std::vector<std::string> mime_types;
394 plugin_list->GetPluginInfoArray( 418 plugin_list->GetPluginInfoArray(
395 url, mime_type, allow_wildcard, use_stale, &plugins, &mime_types); 419 url, mime_type, allow_wildcard, use_stale, &plugins, &mime_types);
396 if (plugins.size() > 1 && 420 if (plugins.size() > 1 &&
397 plugins.back().path == 421 plugins.back().path ==
398 FilePath(webkit::npapi::kDefaultPluginLibraryName)) { 422 FilePath(webkit::npapi::kDefaultPluginLibraryName)) {
(...skipping 11 matching lines...) Expand all
410 &plugins[i])) { 434 &plugins[i])) {
411 *info = plugins[i]; 435 *info = plugins[i];
412 if (actual_mime_type) 436 if (actual_mime_type)
413 *actual_mime_type = mime_types[i]; 437 *actual_mime_type = mime_types[i];
414 return true; 438 return true;
415 } 439 }
416 } 440 }
417 return false; 441 return false;
418 } 442 }
419 443
420 void PluginService::GetPlugins( 444 void PluginService::RefreshPluginList() {
421 const content::ResourceContext& context, 445 GetPluginList()->RefreshPlugins();
422 std::vector<webkit::WebPluginInfo>* plugins) { 446 }
423 // GetPlugins may need to load the plugins, so we need to be 447
424 // on the FILE thread. 448 void PluginService::GetPlugins(const content::ResourceContext& context,
425 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 449 const PluginService::GetPluginsCallback& callback) {
426 webkit::npapi::PluginList* plugin_list = 450 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
427 webkit::npapi::PluginList::Singleton(); 451 base::Bind(&PluginService::GetPluginsInternal, base::Unretained(this),
452 base::Unretained(&context),
jam 2011/09/21 00:04:51 how do you know that the ResourceContext will stil
Robert Sesek 2011/09/21 01:13:44 I was concerned about this too, but was wondering
jam 2011/09/21 06:31:46 You'd have to check with Will Chan about this. It
Bernhard Bauer 2011/09/21 14:31:26 Yes please! Then we can do the filtering on the IO
453 MessageLoop::current()->message_loop_proxy(),
454 callback));
455 }
456
457 void PluginService::GetPlugins(const GetPluginsCallback& callback) {
458 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
459 base::Bind(&PluginService::GetPluginsInternal, base::Unretained(this),
460 base::Unretained(static_cast<content::ResourceContext*>(NULL)),
461 MessageLoop::current()->message_loop_proxy(),
462 callback));
463 }
464
465 void PluginService::GetCachedPluginGroups(
466 std::vector<webkit::npapi::PluginGroup>* groups) {
467 GetPluginList()->GetPluginGroups(false, groups);
468 }
469
470 void PluginService::GetPluginGroups(const GetPluginGroupsCallback& callback) {
471 GetPlugins(base::Bind(&GetPluginsForGroupsCallback, callback));
472 }
473
474 void PluginService::GetPluginsInternal(const content::ResourceContext* context,
475 base::MessageLoopProxy* target_loop,
476 const PluginService::GetPluginsCallback& callback) {
jam 2011/09/21 00:04:51 probably want to copy the DCHECK(BrowserThread::Cu
Robert Sesek 2011/09/21 01:13:44 No, this will be changing shortly anyways.
jam 2011/09/21 06:31:46 On Windows this will still be in-process, so we st
477 // Load all the plugins synchronously.
478 webkit::npapi::PluginList* plugin_list = GetPluginList();
428 std::vector<webkit::WebPluginInfo> all_plugins; 479 std::vector<webkit::WebPluginInfo> all_plugins;
429 plugin_list->GetPlugins(&all_plugins); 480 plugin_list->GetPlugins(&all_plugins);
430 481
431 int child_process_id = -1; 482 if (context) {
432 int routing_id = MSG_ROUTING_NONE; 483 // If there is a context, filter plugins.
433 for (size_t i = 0; i < all_plugins.size(); ++i) { 484 std::vector<webkit::WebPluginInfo> plugins;
434 if (!filter_ || filter_->ShouldUsePlugin(child_process_id, 485
435 routing_id, 486 int child_process_id = -1;
436 &context, 487 int routing_id = MSG_ROUTING_NONE;
437 GURL(), 488 for (size_t i = 0; i < all_plugins.size(); ++i) {
438 GURL(), 489 if (!filter_ || filter_->ShouldUsePlugin(child_process_id,
439 &all_plugins[i])) { 490 routing_id,
440 plugins->push_back(all_plugins[i]); 491 context,
492 GURL(),
493 GURL(),
494 &all_plugins[i])) {
495 plugins.push_back(all_plugins[i]);
496 }
441 } 497 }
498
499 target_loop->PostTask(FROM_HERE,
500 base::Bind(&RunGetPluginsCallback, callback, plugins));
501 } else {
502 // Otherwise, return all plugins.
503 target_loop->PostTask(FROM_HERE,
504 base::Bind(&RunGetPluginsCallback, callback, all_plugins));
442 } 505 }
443 } 506 }
444 507
508 void PluginService::SetPluginListForTesting(
509 webkit::npapi::MockPluginList* plugin_list) {
510 plugin_list_ = plugin_list;
511 }
512
513 webkit::npapi::PluginList* PluginService::GetPluginList() {
514 if (plugin_list_)
515 return plugin_list_;
516 return webkit::npapi::PluginList::Singleton();
517 }
518
445 void PluginService::OnWaitableEventSignaled( 519 void PluginService::OnWaitableEventSignaled(
446 base::WaitableEvent* waitable_event) { 520 base::WaitableEvent* waitable_event) {
447 #if defined(OS_WIN) 521 #if defined(OS_WIN)
448 if (waitable_event == hkcu_event_.get()) { 522 if (waitable_event == hkcu_event_.get()) {
449 hkcu_key_.StartWatching(); 523 hkcu_key_.StartWatching();
450 } else { 524 } else {
451 hklm_key_.StartWatching(); 525 hklm_key_.StartWatching();
452 } 526 }
453 527
454 webkit::npapi::PluginList::Singleton()->RefreshPlugins(); 528 GetPluginList()->RefreshPlugins();
455 PurgePluginListCache(true); 529 PurgePluginListCache(true);
456 #else 530 #else
457 // This event should only get signaled on a Windows machine. 531 // This event should only get signaled on a Windows machine.
458 NOTREACHED(); 532 NOTREACHED();
459 #endif // defined(OS_WIN) 533 #endif // defined(OS_WIN)
460 } 534 }
461 535
462 void PluginService::Observe(int type, 536 void PluginService::Observe(int type,
463 const NotificationSource& source, 537 const NotificationSource& source,
464 const NotificationDetails& details) { 538 const NotificationDetails& details) {
(...skipping 11 matching lines...) Expand all
476 for (RenderProcessHost::iterator it = RenderProcessHost::AllHostsIterator(); 550 for (RenderProcessHost::iterator it = RenderProcessHost::AllHostsIterator();
477 !it.IsAtEnd(); it.Advance()) { 551 !it.IsAtEnd(); it.Advance()) {
478 it.GetCurrentValue()->Send(new ViewMsg_PurgePluginListCache(reload_pages)); 552 it.GetCurrentValue()->Send(new ViewMsg_PurgePluginListCache(reload_pages));
479 } 553 }
480 } 554 }
481 555
482 void PluginService::RegisterPepperPlugins() { 556 void PluginService::RegisterPepperPlugins() {
483 // TODO(abarth): It seems like the PepperPluginRegistry should do this work. 557 // TODO(abarth): It seems like the PepperPluginRegistry should do this work.
484 PepperPluginRegistry::ComputeList(&ppapi_plugins_); 558 PepperPluginRegistry::ComputeList(&ppapi_plugins_);
485 for (size_t i = 0; i < ppapi_plugins_.size(); ++i) { 559 for (size_t i = 0; i < ppapi_plugins_.size(); ++i) {
486 webkit::npapi::PluginList::Singleton()->RegisterInternalPlugin( 560 GetPluginList()->RegisterInternalPlugin(
487 ppapi_plugins_[i].ToWebPluginInfo()); 561 ppapi_plugins_[i].ToWebPluginInfo());
488 } 562 }
489 } 563 }
490 564
491 // There should generally be very few plugins so a brute-force search is fine. 565 // There should generally be very few plugins so a brute-force search is fine.
492 PepperPluginInfo* PluginService::GetRegisteredPpapiPluginInfo( 566 PepperPluginInfo* PluginService::GetRegisteredPpapiPluginInfo(
493 const FilePath& plugin_path) { 567 const FilePath& plugin_path) {
494 PepperPluginInfo* info = NULL; 568 PepperPluginInfo* info = NULL;
495 for (size_t i = 0; i < ppapi_plugins_.size(); i++) { 569 for (size_t i = 0; i < ppapi_plugins_.size(); i++) {
496 if (ppapi_plugins_[i].path == plugin_path) { 570 if (ppapi_plugins_[i].path == plugin_path) {
497 info = &ppapi_plugins_[i]; 571 info = &ppapi_plugins_[i];
498 break; 572 break;
499 } 573 }
500 } 574 }
501 if (info) 575 if (info)
502 return info; 576 return info;
503 // We did not find the plugin in our list. But wait! the plugin can also 577 // We did not find the plugin in our list. But wait! the plugin can also
504 // be a latecomer, as it happens with pepper flash. This information 578 // be a latecomer, as it happens with pepper flash. This information
505 // can be obtained from the PluginList singleton and we can use it to 579 // can be obtained from the PluginList singleton and we can use it to
506 // construct it and add it to the list. This same deal needs to be done 580 // construct it and add it to the list. This same deal needs to be done
507 // in the renderer side in PepperPluginRegistry. 581 // in the renderer side in PepperPluginRegistry.
508 webkit::WebPluginInfo webplugin_info; 582 webkit::WebPluginInfo webplugin_info;
509 if (!webkit::npapi::PluginList::Singleton()->GetPluginInfoByPath( 583 if (!GetPluginList()->GetPluginInfoByPath(plugin_path, &webplugin_info))
510 plugin_path, &webplugin_info))
511 return NULL; 584 return NULL;
512 PepperPluginInfo new_pepper_info; 585 PepperPluginInfo new_pepper_info;
513 if (!MakePepperPluginInfo(webplugin_info, &new_pepper_info)) 586 if (!MakePepperPluginInfo(webplugin_info, &new_pepper_info))
514 return NULL; 587 return NULL;
515 ppapi_plugins_.push_back(new_pepper_info); 588 ppapi_plugins_.push_back(new_pepper_info);
516 return &ppapi_plugins_[ppapi_plugins_.size() - 1]; 589 return &ppapi_plugins_[ppapi_plugins_.size() - 1];
517 } 590 }
518 591
519 #if defined(OS_POSIX) && !defined(OS_MACOSX) 592 #if defined(OS_POSIX) && !defined(OS_MACOSX)
520 // static 593 // static
521 void PluginService::RegisterFilePathWatcher( 594 void PluginService::RegisterFilePathWatcher(
522 FilePathWatcher *watcher, 595 FilePathWatcher *watcher,
523 const FilePath& path, 596 const FilePath& path,
524 FilePathWatcher::Delegate* delegate) { 597 FilePathWatcher::Delegate* delegate) {
525 bool result = watcher->Watch(path, delegate); 598 bool result = watcher->Watch(path, delegate);
526 DCHECK(result); 599 DCHECK(result);
527 } 600 }
528 #endif 601 #endif
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698