OLD | NEW |
---|---|
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 "remoting/host/plugin/host_script_object.h" | 5 #include "remoting/host/plugin/host_script_object.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/message_loop.h" | 8 #include "base/message_loop.h" |
9 #include "base/threading/platform_thread.h" | 9 #include "base/threading/platform_thread.h" |
10 #include "remoting/base/auth_token_util.h" | 10 #include "remoting/base/auth_token_util.h" |
11 #include "remoting/base/util.h" | |
11 #include "remoting/host/chromoting_host.h" | 12 #include "remoting/host/chromoting_host.h" |
12 #include "remoting/host/chromoting_host_context.h" | 13 #include "remoting/host/chromoting_host_context.h" |
13 #include "remoting/host/desktop_environment.h" | 14 #include "remoting/host/desktop_environment.h" |
14 #include "remoting/host/host_config.h" | 15 #include "remoting/host/host_config.h" |
15 #include "remoting/host/host_key_pair.h" | 16 #include "remoting/host/host_key_pair.h" |
16 #include "remoting/host/in_memory_host_config.h" | 17 #include "remoting/host/in_memory_host_config.h" |
17 #include "remoting/host/plugin/host_plugin_utils.h" | 18 #include "remoting/host/plugin/host_plugin_utils.h" |
18 #include "remoting/host/register_support_host_request.h" | 19 #include "remoting/host/register_support_host_request.h" |
19 #include "remoting/host/support_access_verifier.h" | 20 #include "remoting/host/support_access_verifier.h" |
20 | 21 |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
57 const char* kAttrNameRequestedAccessCode = "REQUESTED_ACCESS_CODE"; | 58 const char* kAttrNameRequestedAccessCode = "REQUESTED_ACCESS_CODE"; |
58 const char* kAttrNameReceivedAccessCode = "RECEIVED_ACCESS_CODE"; | 59 const char* kAttrNameReceivedAccessCode = "RECEIVED_ACCESS_CODE"; |
59 const char* kAttrNameConnected = "CONNECTED"; | 60 const char* kAttrNameConnected = "CONNECTED"; |
60 const char* kAttrNameAffirmingConnection = "AFFIRMING_CONNECTION"; | 61 const char* kAttrNameAffirmingConnection = "AFFIRMING_CONNECTION"; |
61 const char* kAttrNameError = "ERROR"; | 62 const char* kAttrNameError = "ERROR"; |
62 | 63 |
63 const int kMaxLoginAttempts = 5; | 64 const int kMaxLoginAttempts = 5; |
64 | 65 |
65 } // namespace | 66 } // namespace |
66 | 67 |
68 // This flag blocks LOGs to the UI if we're already in the middle of logging | |
69 // to the UI. This prevents a potential infinite loop if we encounter an error | |
70 // while sending the log message to the UI. | |
71 static bool g_logging_to_plugin = false; | |
72 static HostNPScriptObject* g_logging_scriptable_object = NULL; | |
73 static logging::LogMessageHandlerFunction g_logging_old_handler = NULL; | |
74 | |
67 HostNPScriptObject::HostNPScriptObject(NPP plugin, NPObject* parent) | 75 HostNPScriptObject::HostNPScriptObject(NPP plugin, NPObject* parent) |
68 : plugin_(plugin), | 76 : plugin_(plugin), |
69 parent_(parent), | 77 parent_(parent), |
70 state_(kDisconnected), | 78 state_(kDisconnected), |
71 log_debug_info_func_(NULL), | 79 log_debug_info_func_(NULL), |
72 on_state_changed_func_(NULL), | 80 on_state_changed_func_(NULL), |
73 np_thread_id_(base::PlatformThread::CurrentId()), | 81 np_thread_id_(base::PlatformThread::CurrentId()), |
74 failed_login_attempts_(0), | 82 failed_login_attempts_(0), |
75 disconnected_event_(true, false) { | 83 disconnected_event_(true, false) { |
76 logger_.reset(new HostPluginLogger(this)); | 84 // Set up log message handler. |
77 logger_->VLog(2, "HostNPScriptObject"); | 85 // Note that this approach doesn't quite support having multiple instances |
86 // of Chromoting running. In that case, the most recently opened tab will | |
87 // grab all the debug log messages, and when any Chromoting tab is closed | |
88 // the logging handler will go away. | |
89 // Since having multiple Chromoting tabs is not a primary use case, and this | |
90 // is just debug logging, we're punting improving debug log support for that | |
91 // case. | |
92 if (g_logging_old_handler == NULL) | |
93 g_logging_old_handler = logging::GetLogMessageHandler(); | |
94 logging::SetLogMessageHandler(&LogToUI); | |
95 g_logging_scriptable_object = this; | |
96 | |
97 VLOG(2) << "HostNPScriptObject"; | |
78 host_context_.SetUITaskPostFunction(base::Bind( | 98 host_context_.SetUITaskPostFunction(base::Bind( |
79 &HostNPScriptObject::PostTaskToNPThread, base::Unretained(this))); | 99 &HostNPScriptObject::PostTaskToNPThread, base::Unretained(this))); |
80 } | 100 } |
81 | 101 |
82 HostNPScriptObject::~HostNPScriptObject() { | 102 HostNPScriptObject::~HostNPScriptObject() { |
83 CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_); | 103 CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_); |
84 | 104 |
85 // Shutdown DesktopEnvironment first so that it doesn't try to post | 105 // Shutdown DesktopEnvironment first so that it doesn't try to post |
86 // tasks on the UI thread while we are stopping the host. | 106 // tasks on the UI thread while we are stopping the host. |
87 desktop_environment_->Shutdown(); | 107 desktop_environment_->Shutdown(); |
88 | 108 |
109 logging::SetLogMessageHandler(g_logging_old_handler_); | |
110 g_logging_old_handler_ = NULL; | |
Wez
2011/08/02 23:45:26
This code isn't symmetric with the constructor; if
| |
111 g_logging_scriptable_object_ = NULL; | |
112 | |
89 // Disconnect synchronously. We cannot disconnect asynchronously | 113 // Disconnect synchronously. We cannot disconnect asynchronously |
90 // here because |host_context_| needs to be stopped on the plugin | 114 // here because |host_context_| needs to be stopped on the plugin |
91 // thread, but the plugin thread may not exist after the instance | 115 // thread, but the plugin thread may not exist after the instance |
92 // is destroyed. | 116 // is destroyed. |
93 destructing_.Set(); | 117 destructing_.Set(); |
94 disconnected_event_.Reset(); | 118 disconnected_event_.Reset(); |
95 DisconnectInternal(); | 119 DisconnectInternal(); |
96 disconnected_event_.Wait(); | 120 disconnected_event_.Wait(); |
97 | 121 |
98 // Stop all threads. | 122 // Stop all threads. |
99 host_context_.Stop(); | 123 host_context_.Stop(); |
100 | 124 |
101 if (log_debug_info_func_) { | 125 if (log_debug_info_func_) { |
102 g_npnetscape_funcs->releaseobject(log_debug_info_func_); | 126 g_npnetscape_funcs->releaseobject(log_debug_info_func_); |
103 } | 127 } |
104 if (on_state_changed_func_) { | 128 if (on_state_changed_func_) { |
105 g_npnetscape_funcs->releaseobject(on_state_changed_func_); | 129 g_npnetscape_funcs->releaseobject(on_state_changed_func_); |
106 } | 130 } |
107 } | 131 } |
108 | 132 |
109 bool HostNPScriptObject::Init() { | 133 bool HostNPScriptObject::Init() { |
110 logger_->VLog(2, "Init"); | 134 VLOG(2) << "Init"; |
111 // TODO(wez): This starts a bunch of threads, which might fail. | 135 // TODO(wez): This starts a bunch of threads, which might fail. |
112 host_context_.Start(); | 136 host_context_.Start(); |
113 return true; | 137 return true; |
114 } | 138 } |
115 | 139 |
116 bool HostNPScriptObject::HasMethod(const std::string& method_name) { | 140 bool HostNPScriptObject::HasMethod(const std::string& method_name) { |
117 logger_->VLog(2, "HasMethod %s", method_name.c_str()); | 141 VLOG(2) << "HasMethod " << method_name; |
118 CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_); | 142 CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_); |
119 return (method_name == kFuncNameConnect || | 143 return (method_name == kFuncNameConnect || |
120 method_name == kFuncNameDisconnect); | 144 method_name == kFuncNameDisconnect); |
121 } | 145 } |
122 | 146 |
123 bool HostNPScriptObject::InvokeDefault(const NPVariant* args, | 147 bool HostNPScriptObject::InvokeDefault(const NPVariant* args, |
124 uint32_t argCount, | 148 uint32_t argCount, |
125 NPVariant* result) { | 149 NPVariant* result) { |
126 logger_->VLog(2, "InvokeDefault"); | 150 VLOG(2) << "InvokeDefault"; |
127 CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_); | 151 CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_); |
128 SetException("exception during default invocation"); | 152 SetException("exception during default invocation"); |
129 return false; | 153 return false; |
130 } | 154 } |
131 | 155 |
132 bool HostNPScriptObject::Invoke(const std::string& method_name, | 156 bool HostNPScriptObject::Invoke(const std::string& method_name, |
133 const NPVariant* args, | 157 const NPVariant* args, |
134 uint32_t argCount, | 158 uint32_t argCount, |
135 NPVariant* result) { | 159 NPVariant* result) { |
136 logger_->VLog(2, "Invoke %s", method_name.c_str()); | 160 VLOG(2) << "Invoke " << method_name; |
137 CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_); | 161 CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_); |
138 if (method_name == kFuncNameConnect) { | 162 if (method_name == kFuncNameConnect) { |
139 return Connect(args, argCount, result); | 163 return Connect(args, argCount, result); |
140 } else if (method_name == kFuncNameDisconnect) { | 164 } else if (method_name == kFuncNameDisconnect) { |
141 return Disconnect(args, argCount, result); | 165 return Disconnect(args, argCount, result); |
142 } else { | 166 } else { |
143 SetException("Invoke: unknown method " + method_name); | 167 SetException("Invoke: unknown method " + method_name); |
144 return false; | 168 return false; |
145 } | 169 } |
146 } | 170 } |
147 | 171 |
148 bool HostNPScriptObject::HasProperty(const std::string& property_name) { | 172 bool HostNPScriptObject::HasProperty(const std::string& property_name) { |
149 logger_->VLog(2, "HasProperty %s", property_name.c_str()); | 173 VLOG(2) << "HasProperty " << property_name; |
150 CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_); | 174 CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_); |
151 return (property_name == kAttrNameAccessCode || | 175 return (property_name == kAttrNameAccessCode || |
152 property_name == kAttrNameAccessCodeLifetime || | 176 property_name == kAttrNameAccessCodeLifetime || |
153 property_name == kAttrNameState || | 177 property_name == kAttrNameState || |
154 property_name == kAttrNameLogDebugInfo || | 178 property_name == kAttrNameLogDebugInfo || |
155 property_name == kAttrNameOnStateChanged || | 179 property_name == kAttrNameOnStateChanged || |
156 property_name == kAttrNameDisconnected || | 180 property_name == kAttrNameDisconnected || |
157 property_name == kAttrNameRequestedAccessCode || | 181 property_name == kAttrNameRequestedAccessCode || |
158 property_name == kAttrNameReceivedAccessCode || | 182 property_name == kAttrNameReceivedAccessCode || |
159 property_name == kAttrNameConnected || | 183 property_name == kAttrNameConnected || |
160 property_name == kAttrNameAffirmingConnection || | 184 property_name == kAttrNameAffirmingConnection || |
161 property_name == kAttrNameError); | 185 property_name == kAttrNameError); |
162 } | 186 } |
163 | 187 |
164 bool HostNPScriptObject::GetProperty(const std::string& property_name, | 188 bool HostNPScriptObject::GetProperty(const std::string& property_name, |
165 NPVariant* result) { | 189 NPVariant* result) { |
166 logger_->VLog(2, "GetProperty %s", property_name.c_str()); | 190 VLOG(2) << "GetProperty " << property_name; |
167 CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_); | 191 CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_); |
168 if (!result) { | 192 if (!result) { |
169 SetException("GetProperty: NULL result"); | 193 SetException("GetProperty: NULL result"); |
170 return false; | 194 return false; |
171 } | 195 } |
172 | 196 |
173 if (property_name == kAttrNameOnStateChanged) { | 197 if (property_name == kAttrNameOnStateChanged) { |
174 OBJECT_TO_NPVARIANT(on_state_changed_func_, *result); | 198 OBJECT_TO_NPVARIANT(on_state_changed_func_, *result); |
175 return true; | 199 return true; |
176 } else if (property_name == kAttrNameLogDebugInfo) { | 200 } else if (property_name == kAttrNameLogDebugInfo) { |
(...skipping 27 matching lines...) Expand all Loading... | |
204 INT32_TO_NPVARIANT(kError, *result); | 228 INT32_TO_NPVARIANT(kError, *result); |
205 return true; | 229 return true; |
206 } else { | 230 } else { |
207 SetException("GetProperty: unsupported property " + property_name); | 231 SetException("GetProperty: unsupported property " + property_name); |
208 return false; | 232 return false; |
209 } | 233 } |
210 } | 234 } |
211 | 235 |
212 bool HostNPScriptObject::SetProperty(const std::string& property_name, | 236 bool HostNPScriptObject::SetProperty(const std::string& property_name, |
213 const NPVariant* value) { | 237 const NPVariant* value) { |
214 logger_->VLog(2, "SetProperty %s", property_name.c_str()); | 238 VLOG(2) << "SetProperty " << property_name; |
215 CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_); | 239 CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_); |
216 | 240 |
217 if (property_name == kAttrNameOnStateChanged) { | 241 if (property_name == kAttrNameOnStateChanged) { |
218 if (NPVARIANT_IS_OBJECT(*value)) { | 242 if (NPVARIANT_IS_OBJECT(*value)) { |
219 if (on_state_changed_func_) { | 243 if (on_state_changed_func_) { |
220 g_npnetscape_funcs->releaseobject(on_state_changed_func_); | 244 g_npnetscape_funcs->releaseobject(on_state_changed_func_); |
221 } | 245 } |
222 on_state_changed_func_ = NPVARIANT_TO_OBJECT(*value); | 246 on_state_changed_func_ = NPVARIANT_TO_OBJECT(*value); |
223 if (on_state_changed_func_) { | 247 if (on_state_changed_func_) { |
224 g_npnetscape_funcs->retainobject(on_state_changed_func_); | 248 g_npnetscape_funcs->retainobject(on_state_changed_func_); |
(...skipping 20 matching lines...) Expand all Loading... | |
245 SetException("SetProperty: unexpected type for property " + | 269 SetException("SetProperty: unexpected type for property " + |
246 property_name); | 270 property_name); |
247 } | 271 } |
248 return false; | 272 return false; |
249 } | 273 } |
250 | 274 |
251 return false; | 275 return false; |
252 } | 276 } |
253 | 277 |
254 bool HostNPScriptObject::RemoveProperty(const std::string& property_name) { | 278 bool HostNPScriptObject::RemoveProperty(const std::string& property_name) { |
255 logger_->VLog(2, "RemoveProperty %s", property_name.c_str()); | 279 VLOG(2) << "RemoveProperty " << property_name; |
256 CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_); | 280 CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_); |
257 return false; | 281 return false; |
258 } | 282 } |
259 | 283 |
260 bool HostNPScriptObject::Enumerate(std::vector<std::string>* values) { | 284 bool HostNPScriptObject::Enumerate(std::vector<std::string>* values) { |
261 logger_->VLog(2, "Enumerate"); | 285 VLOG(2) << "Enumerate"; |
262 CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_); | 286 CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_); |
263 const char* entries[] = { | 287 const char* entries[] = { |
264 kAttrNameAccessCode, | 288 kAttrNameAccessCode, |
265 kAttrNameState, | 289 kAttrNameState, |
266 kAttrNameLogDebugInfo, | 290 kAttrNameLogDebugInfo, |
267 kAttrNameOnStateChanged, | 291 kAttrNameOnStateChanged, |
268 kFuncNameConnect, | 292 kFuncNameConnect, |
269 kFuncNameDisconnect, | 293 kFuncNameDisconnect, |
270 kAttrNameDisconnected, | 294 kAttrNameDisconnected, |
271 kAttrNameRequestedAccessCode, | 295 kAttrNameRequestedAccessCode, |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
305 | 329 |
306 OnStateChanged(kDisconnected); | 330 OnStateChanged(kDisconnected); |
307 } | 331 } |
308 | 332 |
309 // string uid, string auth_token | 333 // string uid, string auth_token |
310 bool HostNPScriptObject::Connect(const NPVariant* args, | 334 bool HostNPScriptObject::Connect(const NPVariant* args, |
311 uint32_t arg_count, | 335 uint32_t arg_count, |
312 NPVariant* result) { | 336 NPVariant* result) { |
313 CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_); | 337 CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_); |
314 | 338 |
315 LogDebugInfo("Connecting..."); | 339 LOG(INFO) << "Connecting..."; |
316 | 340 |
317 if (arg_count != 2) { | 341 if (arg_count != 2) { |
318 SetException("connect: bad number of arguments"); | 342 SetException("connect: bad number of arguments"); |
319 return false; | 343 return false; |
320 } | 344 } |
321 | 345 |
322 std::string uid = StringFromNPVariant(args[0]); | 346 std::string uid = StringFromNPVariant(args[0]); |
323 if (uid.empty()) { | 347 if (uid.empty()) { |
324 SetException("connect: bad uid argument"); | 348 SetException("connect: bad uid argument"); |
325 return false; | 349 return false; |
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
475 return; | 499 return; |
476 | 500 |
477 if (!host_context_.IsUIThread()) { | 501 if (!host_context_.IsUIThread()) { |
478 host_context_.PostTaskToUIThread( | 502 host_context_.PostTaskToUIThread( |
479 FROM_HERE, base::Bind(&HostNPScriptObject::OnStateChanged, | 503 FROM_HERE, base::Bind(&HostNPScriptObject::OnStateChanged, |
480 base::Unretained(this), state)); | 504 base::Unretained(this), state)); |
481 return; | 505 return; |
482 } | 506 } |
483 state_ = state; | 507 state_ = state; |
484 if (on_state_changed_func_) { | 508 if (on_state_changed_func_) { |
485 logger_->VLog(2, "Calling state changed %s", state); | 509 VLOG(2) << "Calling state changed " << state; |
486 bool is_good = InvokeAndIgnoreResult(on_state_changed_func_, NULL, 0); | 510 bool is_good = InvokeAndIgnoreResult(on_state_changed_func_, NULL, 0); |
487 LOG_IF(ERROR, !is_good) << "OnStateChanged failed"; | 511 LOG_IF(ERROR, !is_good) << "OnStateChanged failed"; |
488 } | 512 } |
489 } | 513 } |
490 | 514 |
515 // static | |
516 bool HostNPScriptObject::LogToUI(int severity, const char* file, int line, | |
517 size_t message_start, | |
518 const std::string& str) { | |
519 if (g_logging_scriptable_object) { | |
520 std::string message = remoting::GetTimestampString(); | |
521 message += (str.c_str() + message_start); | |
522 g_logging_scriptable_object->LogDebugInfo(message); | |
523 } | |
524 if (g_logging_old_handler) | |
525 return (g_logging_old_handler)(severity, file, line, message_start, str); | |
526 return false; | |
527 } | |
528 | |
491 void HostNPScriptObject::LogDebugInfo(const std::string& message) { | 529 void HostNPScriptObject::LogDebugInfo(const std::string& message) { |
492 if (destructing_.IsSet()) | 530 if (destructing_.IsSet()) |
493 return; | 531 return; |
494 | 532 |
495 if (!host_context_.IsUIThread()) { | 533 if (!host_context_.IsUIThread()) { |
496 host_context_.PostTaskToUIThread( | 534 host_context_.PostTaskToUIThread( |
497 FROM_HERE, base::Bind(&HostNPScriptObject::LogDebugInfo, | 535 FROM_HERE, base::Bind(&HostNPScriptObject::LogDebugInfo, |
498 base::Unretained(this), message)); | 536 base::Unretained(this), message)); |
499 return; | 537 return; |
500 } | 538 } |
501 if (log_debug_info_func_) { | 539 if (log_debug_info_func_ && !g_logging_to_plugin) { |
Sergey Ulanov
2011/08/02 18:15:52
Not sure why we need |g_logging_to_plugin| here. C
garykac
2011/08/02 23:09:51
Added comments and moved it into the static LogToU
| |
502 NPVariant* arg = new NPVariant(); | 540 NPVariant* arg = new NPVariant(); |
503 STRINGZ_TO_NPVARIANT(message.c_str(), *arg); | 541 STRINGZ_TO_NPVARIANT(message.c_str(), *arg); |
542 g_logging_to_plugin = true; | |
504 bool is_good = InvokeAndIgnoreResult(log_debug_info_func_, arg, 1); | 543 bool is_good = InvokeAndIgnoreResult(log_debug_info_func_, arg, 1); |
544 g_logging_to_plugin = false; | |
505 LOG_IF(ERROR, !is_good) << "LogDebugInfo failed"; | 545 LOG_IF(ERROR, !is_good) << "LogDebugInfo failed"; |
506 } | 546 } |
507 } | 547 } |
508 | 548 |
509 void HostNPScriptObject::SetException(const std::string& exception_string) { | 549 void HostNPScriptObject::SetException(const std::string& exception_string) { |
510 CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_); | 550 CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_); |
511 g_npnetscape_funcs->setexception(parent_, exception_string.c_str()); | 551 g_npnetscape_funcs->setexception(parent_, exception_string.c_str()); |
512 LogDebugInfo(exception_string); | 552 LOG(INFO) << exception_string; |
513 } | 553 } |
514 | 554 |
515 bool HostNPScriptObject::InvokeAndIgnoreResult(NPObject* func, | 555 bool HostNPScriptObject::InvokeAndIgnoreResult(NPObject* func, |
516 const NPVariant* args, | 556 const NPVariant* args, |
517 uint32_t argCount) { | 557 uint32_t argCount) { |
518 NPVariant np_result; | 558 NPVariant np_result; |
519 bool is_good = g_npnetscape_funcs->invokeDefault(plugin_, func, args, | 559 bool is_good = g_npnetscape_funcs->invokeDefault(plugin_, func, args, |
520 argCount, &np_result); | 560 argCount, &np_result); |
521 if (is_good) | 561 if (is_good) |
522 g_npnetscape_funcs->releasevariantvalue(&np_result); | 562 g_npnetscape_funcs->releasevariantvalue(&np_result); |
(...skipping 15 matching lines...) Expand all Loading... | |
538 } | 578 } |
539 | 579 |
540 // static | 580 // static |
541 void HostNPScriptObject::NPTaskSpringboard(void* task) { | 581 void HostNPScriptObject::NPTaskSpringboard(void* task) { |
542 base::Closure* real_task = reinterpret_cast<base::Closure*>(task); | 582 base::Closure* real_task = reinterpret_cast<base::Closure*>(task); |
543 real_task->Run(); | 583 real_task->Run(); |
544 delete real_task; | 584 delete real_task; |
545 } | 585 } |
546 | 586 |
547 } // namespace remoting | 587 } // namespace remoting |
OLD | NEW |