| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 * Copyright (c) 2011 The Native Client Authors. All rights reserved. | |
| 3 * Use of this source code is governed by a BSD-style license that can be | |
| 4 * found in the LICENSE file. | |
| 5 */ | |
| 6 | |
| 7 #define NACL_LOG_MODULE_NAME "Plugin::ServiceRuntime" | |
| 8 | |
| 9 #include "native_client/src/trusted/plugin/service_runtime.h" | |
| 10 | |
| 11 #include <string.h> | |
| 12 #include <map> | |
| 13 #include <set> | |
| 14 #include <string> | |
| 15 #include <utility> | |
| 16 #include <vector> | |
| 17 | |
| 18 #include "native_client/src/include/portability_io.h" | |
| 19 #include "native_client/src/include/nacl_scoped_ptr.h" | |
| 20 #include "native_client/src/include/nacl_macros.h" | |
| 21 #include "native_client/src/include/nacl_string.h" | |
| 22 #include "native_client/src/shared/imc/nacl_imc.h" | |
| 23 #include "native_client/src/shared/platform/nacl_check.h" | |
| 24 #include "native_client/src/shared/platform/nacl_log.h" | |
| 25 #include "native_client/src/shared/platform/nacl_sync.h" | |
| 26 #include "native_client/src/shared/platform/nacl_sync_checked.h" | |
| 27 #include "native_client/src/shared/platform/nacl_sync_raii.h" | |
| 28 #include "native_client/src/shared/platform/scoped_ptr_refcount.h" | |
| 29 #include "native_client/src/trusted/desc/nacl_desc_imc.h" | |
| 30 #include "native_client/src/trusted/desc/nrd_xfer.h" | |
| 31 #include "native_client/src/trusted/desc/nrd_xfer_effector.h" | |
| 32 #include "native_client/src/trusted/handle_pass/browser_handle.h" | |
| 33 #include "native_client/src/trusted/nonnacl_util/sel_ldr_launcher.h" | |
| 34 | |
| 35 #include "native_client/src/trusted/plugin/browser_interface.h" | |
| 36 #include "native_client/src/trusted/plugin/manifest.h" | |
| 37 #include "native_client/src/trusted/plugin/plugin.h" | |
| 38 #include "native_client/src/trusted/plugin/plugin_error.h" | |
| 39 #include "native_client/src/trusted/plugin/scriptable_handle.h" | |
| 40 #include "native_client/src/trusted/plugin/srpc_client.h" | |
| 41 #include "native_client/src/trusted/plugin/utility.h" | |
| 42 | |
| 43 #include "native_client/src/trusted/weak_ref/call_on_main_thread.h" | |
| 44 | |
| 45 #include "native_client/src/trusted/service_runtime/nacl_error_code.h" | |
| 46 #include "native_client/src/trusted/service_runtime/include/sys/nacl_imc_api.h" | |
| 47 | |
| 48 #include "ppapi/c/pp_errors.h" | |
| 49 #include "ppapi/cpp/core.h" | |
| 50 #include "ppapi/cpp/completion_callback.h" | |
| 51 | |
| 52 using std::vector; | |
| 53 | |
| 54 namespace plugin { | |
| 55 | |
| 56 PluginReverseInterface::PluginReverseInterface( | |
| 57 nacl::WeakRefAnchor* anchor, | |
| 58 Plugin* plugin, | |
| 59 pp::CompletionCallback init_done_cb) | |
| 60 : anchor_(anchor), | |
| 61 plugin_(plugin), | |
| 62 shutting_down_(false), | |
| 63 init_done_cb_(init_done_cb) { | |
| 64 NaClXMutexCtor(&mu_); | |
| 65 NaClXCondVarCtor(&cv_); | |
| 66 } | |
| 67 | |
| 68 PluginReverseInterface::~PluginReverseInterface() { | |
| 69 NaClCondVarDtor(&cv_); | |
| 70 NaClMutexDtor(&mu_); | |
| 71 } | |
| 72 | |
| 73 void PluginReverseInterface::ShutDown() { | |
| 74 nacl::MutexLocker take(&mu_); | |
| 75 shutting_down_ = true; | |
| 76 NaClXCondVarBroadcast(&cv_); | |
| 77 } | |
| 78 | |
| 79 void PluginReverseInterface::Log(nacl::string message) { | |
| 80 LogToJavaScriptConsoleResource* continuation = | |
| 81 new LogToJavaScriptConsoleResource(message); | |
| 82 CHECK(continuation != NULL); | |
| 83 NaClLog(4, "PluginReverseInterface::Log(%s)\n", message.c_str()); | |
| 84 plugin::WeakRefCallOnMainThread( | |
| 85 anchor_, | |
| 86 0, /* delay in ms */ | |
| 87 this, | |
| 88 &plugin::PluginReverseInterface::Log_MainThreadContinuation, | |
| 89 continuation); | |
| 90 } | |
| 91 | |
| 92 void PluginReverseInterface::StartupInitializationComplete() { | |
| 93 NaClLog(0, "PluginReverseInterface::StartupInitializationComplete\n"); | |
| 94 if (init_done_cb_.pp_completion_callback().func != NULL) { | |
| 95 NaClLog(0, | |
| 96 "PluginReverseInterface::StartupInitializationComplete:" | |
| 97 " invoking CB\n"); | |
| 98 pp::Module::Get()->core()->CallOnMainThread(0, init_done_cb_, PP_OK); | |
| 99 } else { | |
| 100 NaClLog(0, | |
| 101 "PluginReverseInterface::StartupInitializationComplete:" | |
| 102 " init_done_cb_ not valid, skipping.\n"); | |
| 103 } | |
| 104 } | |
| 105 | |
| 106 void PluginReverseInterface::Log_MainThreadContinuation( | |
| 107 LogToJavaScriptConsoleResource* p, | |
| 108 int32_t err) { | |
| 109 UNREFERENCED_PARAMETER(err); | |
| 110 NaClLog(4, | |
| 111 "PluginReverseInterface::Log_MainThreadContinuation(%s)\n", | |
| 112 p->message.c_str()); | |
| 113 plugin_->browser_interface()->AddToConsole(static_cast<Plugin*>(plugin_), | |
| 114 p->message); | |
| 115 } | |
| 116 | |
| 117 bool PluginReverseInterface::EnumerateManifestKeys( | |
| 118 std::set<nacl::string>* out_keys) { | |
| 119 Manifest const* mp = plugin_->manifest(); | |
| 120 | |
| 121 if (!mp->GetFileKeys(out_keys)) { | |
| 122 return false; | |
| 123 } | |
| 124 | |
| 125 return true; | |
| 126 } | |
| 127 | |
| 128 // TODO(bsy): OpenManifestEntry should use the manifest to ResolveKey | |
| 129 // and invoke StreamAsFile with a completion callback that invokes | |
| 130 // GetPOSIXFileDesc. | |
| 131 bool PluginReverseInterface::OpenManifestEntry(nacl::string url_key, | |
| 132 int32_t* out_desc) { | |
| 133 ErrorInfo error_info; | |
| 134 bool is_portable = false; | |
| 135 bool op_complete = false; // NB: mu_ and cv_ also controls access to this! | |
| 136 OpenManifestEntryResource* to_open = | |
| 137 new OpenManifestEntryResource(url_key, out_desc, | |
| 138 &error_info, &is_portable, &op_complete); | |
| 139 CHECK(to_open != NULL); | |
| 140 NaClLog(4, "PluginReverseInterface::OpenManifestEntry: %s\n", | |
| 141 url_key.c_str()); | |
| 142 // This assumes we are not on the main thread. If false, we deadlock. | |
| 143 plugin::WeakRefCallOnMainThread( | |
| 144 anchor_, | |
| 145 0, | |
| 146 this, | |
| 147 &plugin::PluginReverseInterface::OpenManifestEntry_MainThreadContinuation, | |
| 148 to_open); | |
| 149 NaClLog(4, | |
| 150 "PluginReverseInterface::OpenManifestEntry:" | |
| 151 " waiting on main thread\n"); | |
| 152 bool shutting_down; | |
| 153 do { | |
| 154 nacl::MutexLocker take(&mu_); | |
| 155 for (;;) { | |
| 156 NaClLog(4, | |
| 157 "PluginReverseInterface::OpenManifestEntry:" | |
| 158 " got lock, checking shutdown and completion: (%s, %s)\n", | |
| 159 shutting_down_ ? "yes" : "no", | |
| 160 op_complete ? "yes" : "no"); | |
| 161 shutting_down = shutting_down_; | |
| 162 if (op_complete || shutting_down) { | |
| 163 NaClLog(4, | |
| 164 "PluginReverseInterface::OpenManifestEntry:" | |
| 165 " done!\n"); | |
| 166 break; | |
| 167 } | |
| 168 NaClXCondVarWait(&cv_, &mu_); | |
| 169 } | |
| 170 } while (0); | |
| 171 if (shutting_down) { | |
| 172 NaClLog(4, | |
| 173 "PluginReverseInterface::OpenManifestEntry:" | |
| 174 " plugin is shutting down\n"); | |
| 175 return false; | |
| 176 } | |
| 177 // out_desc has the returned descriptor if successful, else -1. | |
| 178 | |
| 179 // The caller is responsible for not closing *out_desc. If it is | |
| 180 // closed prematurely, then another open could re-use the OS | |
| 181 // descriptor, confusing the opened_ map. If the caller is going to | |
| 182 // want to make a NaClDesc object and transfer it etc., then the | |
| 183 // caller should DUP the descriptor (but remember the original | |
| 184 // value) for use by the NaClDesc object, which closes when the | |
| 185 // object is destroyed. | |
| 186 NaClLog(4, | |
| 187 "PluginReverseInterface::OpenManifestEntry:" | |
| 188 " *out_desc = %d\n", | |
| 189 *out_desc); | |
| 190 if (*out_desc == -1) { | |
| 191 // TODO(bsy,ncbray): what else should we do with the error? This | |
| 192 // is a runtime error that may simply be a programming error in | |
| 193 // the untrusted code, or it may be something else wrong w/ the | |
| 194 // manifest. | |
| 195 NaClLog(4, | |
| 196 "OpenManifestEntry: failed for key %s, code %d (%s)\n", | |
| 197 url_key.c_str(), | |
| 198 error_info.error_code(), | |
| 199 error_info.message().c_str()); | |
| 200 } | |
| 201 return true; | |
| 202 } | |
| 203 | |
| 204 void PluginReverseInterface::OpenManifestEntry_MainThreadContinuation( | |
| 205 OpenManifestEntryResource* p, | |
| 206 int32_t err) { | |
| 207 OpenManifestEntryResource *open_cont; | |
| 208 UNREFERENCED_PARAMETER(err); | |
| 209 // CallOnMainThread continuations always called with err == PP_OK. | |
| 210 | |
| 211 NaClLog(4, "Entered OpenManifestEntry_MainThreadContinuation\n"); | |
| 212 | |
| 213 std::string mapped_url; | |
| 214 if (!plugin_->manifest()->ResolveKey(p->url, &mapped_url, | |
| 215 p->error_info, p->is_portable)) { | |
| 216 NaClLog(4, "OpenManifestEntry_MainThreadContinuation: ResolveKey failed\n"); | |
| 217 // Failed, and error_info has the details on what happened. Wake | |
| 218 // up requesting thread -- we are done. | |
| 219 nacl::MutexLocker take(&mu_); | |
| 220 *p->op_complete_ptr = true; // done... | |
| 221 *p->out_desc = -1; // but failed. | |
| 222 NaClXCondVarBroadcast(&cv_); | |
| 223 return; | |
| 224 } | |
| 225 NaClLog(4, | |
| 226 "OpenManifestEntry_MainThreadContinuation: ResolveKey: %s -> %s\n", | |
| 227 p->url.c_str(), mapped_url.c_str()); | |
| 228 | |
| 229 open_cont = new OpenManifestEntryResource(*p); // copy ctor! | |
| 230 CHECK(open_cont != NULL); | |
| 231 open_cont->url = mapped_url; | |
| 232 pp::CompletionCallback stream_cc = WeakRefNewCallback( | |
| 233 anchor_, | |
| 234 this, | |
| 235 &PluginReverseInterface::StreamAsFile_MainThreadContinuation, | |
| 236 open_cont); | |
| 237 if (!plugin_->StreamAsFile(mapped_url, stream_cc.pp_completion_callback())) { | |
| 238 NaClLog(4, | |
| 239 "OpenManifestEntry_MainThreadContinuation: StreamAsFile failed\n"); | |
| 240 nacl::MutexLocker take(&mu_); | |
| 241 *p->op_complete_ptr = true; // done... | |
| 242 *p->out_desc = -1; // but failed. | |
| 243 p->error_info->SetReport(ERROR_MANIFEST_OPEN, | |
| 244 "ServiceRuntime: StreamAsFile failed"); | |
| 245 NaClXCondVarBroadcast(&cv_); | |
| 246 return; | |
| 247 } | |
| 248 NaClLog(4, | |
| 249 "OpenManifestEntry_MainThreadContinuation: StreamAsFile okay\n"); | |
| 250 // p is deleted automatically | |
| 251 } | |
| 252 | |
| 253 void PluginReverseInterface::StreamAsFile_MainThreadContinuation( | |
| 254 OpenManifestEntryResource* p, | |
| 255 int32_t result) { | |
| 256 NaClLog(4, | |
| 257 "Entered StreamAsFile_MainThreadContinuation\n"); | |
| 258 | |
| 259 nacl::MutexLocker take(&mu_); | |
| 260 if (result == PP_OK) { | |
| 261 NaClLog(4, "StreamAsFile_MainThreadContinuation: GetPOSIXFileDesc(%s)\n", | |
| 262 p->url.c_str()); | |
| 263 *p->out_desc = plugin_->GetPOSIXFileDesc(p->url); | |
| 264 NaClLog(4, | |
| 265 "StreamAsFile_MainThreadContinuation: PP_OK, desc %d\n", | |
| 266 *p->out_desc); | |
| 267 } else { | |
| 268 NaClLog(4, | |
| 269 "StreamAsFile_MainThreadContinuation: !PP_OK, setting desc -1\n"); | |
| 270 *p->out_desc = -1; | |
| 271 p->error_info->SetReport(ERROR_MANIFEST_OPEN, | |
| 272 "Plugin StreamAsFile failed at callback"); | |
| 273 } | |
| 274 *p->op_complete_ptr = true; | |
| 275 NaClXCondVarBroadcast(&cv_); | |
| 276 } | |
| 277 | |
| 278 bool PluginReverseInterface::CloseManifestEntry(int32_t desc) { | |
| 279 bool op_complete; | |
| 280 bool op_result; | |
| 281 CloseManifestEntryResource* to_close = | |
| 282 new CloseManifestEntryResource(desc, &op_complete, &op_result); | |
| 283 | |
| 284 bool shutting_down; | |
| 285 plugin::WeakRefCallOnMainThread( | |
| 286 anchor_, | |
| 287 0, | |
| 288 this, | |
| 289 &plugin::PluginReverseInterface:: | |
| 290 CloseManifestEntry_MainThreadContinuation, | |
| 291 to_close); | |
| 292 // wait for completion or surf-away. | |
| 293 do { | |
| 294 nacl::MutexLocker take(&mu_); | |
| 295 for (;;) { | |
| 296 shutting_down = shutting_down_; | |
| 297 if (op_complete || shutting_down) { | |
| 298 break; | |
| 299 } | |
| 300 NaClXCondVarWait(&cv_, &mu_); | |
| 301 } | |
| 302 } while (0); | |
| 303 | |
| 304 if (shutting_down) return false; | |
| 305 // op_result true if close was successful; false otherwise (e.g., bad desc). | |
| 306 return op_result; | |
| 307 } | |
| 308 | |
| 309 void PluginReverseInterface::CloseManifestEntry_MainThreadContinuation( | |
| 310 CloseManifestEntryResource* cls, | |
| 311 int32_t err) { | |
| 312 UNREFERENCED_PARAMETER(err); | |
| 313 | |
| 314 nacl::MutexLocker take(&mu_); | |
| 315 // TODO(bsy): once the plugin has a reliable way to report that the | |
| 316 // file usage is done -- and sel_ldr uses this RPC call -- we should | |
| 317 // tell the plugin that the associated resources can be freed. | |
| 318 *cls->op_result_ptr = true; | |
| 319 *cls->op_complete_ptr = true; | |
| 320 NaClXCondVarBroadcast(&cv_); | |
| 321 // cls automatically deleted | |
| 322 } | |
| 323 | |
| 324 ServiceRuntime::ServiceRuntime(Plugin* plugin, | |
| 325 pp::CompletionCallback init_done_cb) | |
| 326 : plugin_(plugin), | |
| 327 browser_interface_(plugin->browser_interface()), | |
| 328 reverse_service_(NULL), | |
| 329 subprocess_(NULL), | |
| 330 async_receive_desc_(NULL), | |
| 331 async_send_desc_(NULL), | |
| 332 anchor_(new nacl::WeakRefAnchor()), | |
| 333 rev_interface_(new PluginReverseInterface(anchor_, plugin, | |
| 334 init_done_cb)) { | |
| 335 NaClSrpcChannelInitialize(&command_channel_); | |
| 336 } | |
| 337 | |
| 338 bool ServiceRuntime::InitCommunication(nacl::DescWrapper* nacl_desc, | |
| 339 ErrorInfo* error_info) { | |
| 340 PLUGIN_PRINTF(("ServiceRuntime::InitCommunication" | |
| 341 " (this=%p, subprocess=%p)\n", | |
| 342 static_cast<void*>(this), | |
| 343 static_cast<void*>(subprocess_.get()))); | |
| 344 // Create the command channel to the sel_ldr and load the nexe from nacl_desc. | |
| 345 if (!subprocess_->SetupCommandAndLoad(&command_channel_, nacl_desc)) { | |
| 346 error_info->SetReport(ERROR_SEL_LDR_COMMUNICATION_CMD_CHANNEL, | |
| 347 "ServiceRuntime: command channel creation failed"); | |
| 348 return false; | |
| 349 } | |
| 350 // Hook up the reverse service channel. We are the IMC client, but | |
| 351 // provide SRPC service. | |
| 352 NaClDesc* out_conn_cap; | |
| 353 NaClSrpcResultCodes rpc_result = | |
| 354 NaClSrpcInvokeBySignature(&command_channel_, | |
| 355 "reverse_setup::h", | |
| 356 &out_conn_cap); | |
| 357 | |
| 358 if (NACL_SRPC_RESULT_OK != rpc_result) { | |
| 359 error_info->SetReport(ERROR_SEL_LDR_COMMUNICATION_REV_SETUP, | |
| 360 "ServiceRuntime: reverse setup rpc failed"); | |
| 361 return false; | |
| 362 } | |
| 363 // Get connection capability to service runtime where the IMC | |
| 364 // server/SRPC client is waiting for a rendezvous. | |
| 365 PLUGIN_PRINTF(("ServiceRuntime: got 0x%"NACL_PRIxPTR"\n", | |
| 366 (uintptr_t) out_conn_cap)); | |
| 367 nacl::DescWrapper* conn_cap = plugin_->wrapper_factory()->MakeGenericCleanup( | |
| 368 out_conn_cap); | |
| 369 if (conn_cap == NULL) { | |
| 370 error_info->SetReport(ERROR_SEL_LDR_COMMUNICATION_WRAPPER, | |
| 371 "ServiceRuntime: wrapper allocation failure"); | |
| 372 return false; | |
| 373 } | |
| 374 out_conn_cap = NULL; // ownership passed | |
| 375 reverse_service_ = new nacl::ReverseService(conn_cap, rev_interface_->Ref()); | |
| 376 if (!reverse_service_->Start()) { | |
| 377 error_info->SetReport(ERROR_SEL_LDR_COMMUNICATION_REV_SERVICE, | |
| 378 "ServiceRuntime: starting reverse services failed"); | |
| 379 return false; | |
| 380 } | |
| 381 | |
| 382 #if NACL_WINDOWS && !defined(NACL_STANDALONE) | |
| 383 // Establish the communication for handle passing protocol | |
| 384 struct NaClDesc* desc = NaClHandlePassBrowserGetSocketAddress(); | |
| 385 | |
| 386 DWORD my_pid = GetCurrentProcessId(); | |
| 387 nacl::Handle my_handle = GetCurrentProcess(); | |
| 388 nacl::Handle my_handle_in_selldr; | |
| 389 | |
| 390 if (!DuplicateHandle(GetCurrentProcess(), | |
| 391 my_handle, | |
| 392 subprocess_->child_process(), | |
| 393 &my_handle_in_selldr, | |
| 394 PROCESS_DUP_HANDLE, | |
| 395 FALSE, | |
| 396 0)) { | |
| 397 error_info->SetReport(ERROR_SEL_LDR_HANDLE_PASSING, | |
| 398 "ServiceRuntime: failed handle passing protocol"); | |
| 399 return false; | |
| 400 } | |
| 401 | |
| 402 rpc_result = | |
| 403 NaClSrpcInvokeBySignature(&command_channel_, | |
| 404 "init_handle_passing:hii:", | |
| 405 desc, | |
| 406 my_pid, | |
| 407 reinterpret_cast<int>(my_handle_in_selldr)); | |
| 408 | |
| 409 if (NACL_SRPC_RESULT_OK != rpc_result) { | |
| 410 error_info->SetReport(ERROR_SEL_LDR_HANDLE_PASSING, | |
| 411 "ServiceRuntime: failed handle passing protocol"); | |
| 412 return false; | |
| 413 } | |
| 414 #endif | |
| 415 // start the module. otherwise we cannot connect for multimedia | |
| 416 // subsystem since that is handled by user-level code (not secure!) | |
| 417 // in libsrpc. | |
| 418 int load_status = -1; | |
| 419 rpc_result = | |
| 420 NaClSrpcInvokeBySignature(&command_channel_, | |
| 421 "start_module::i", | |
| 422 &load_status); | |
| 423 | |
| 424 if (NACL_SRPC_RESULT_OK != rpc_result) { | |
| 425 error_info->SetReport(ERROR_SEL_LDR_START_MODULE, | |
| 426 "ServiceRuntime: could not start nacl module"); | |
| 427 return false; | |
| 428 } | |
| 429 PLUGIN_PRINTF(("ServiceRuntime::InitCommunication (load_status=%d)\n", | |
| 430 load_status)); | |
| 431 plugin_->ReportSelLdrLoadStatus(load_status); | |
| 432 if (LOAD_OK != load_status) { | |
| 433 error_info->SetReport( | |
| 434 ERROR_SEL_LDR_START_STATUS, | |
| 435 NaClErrorString(static_cast<NaClErrorCode>(load_status))); | |
| 436 return false; | |
| 437 } | |
| 438 return true; | |
| 439 } | |
| 440 | |
| 441 bool ServiceRuntime::Start(nacl::DescWrapper* nacl_desc, | |
| 442 ErrorInfo* error_info) { | |
| 443 PLUGIN_PRINTF(("ServiceRuntime::Start (nacl_desc=%p)\n", | |
| 444 reinterpret_cast<void*>(nacl_desc))); | |
| 445 | |
| 446 nacl::scoped_ptr<nacl::SelLdrLauncher> | |
| 447 tmp_subprocess(new(std::nothrow) nacl::SelLdrLauncher()); | |
| 448 if (NULL == tmp_subprocess.get()) { | |
| 449 PLUGIN_PRINTF(("ServiceRuntime::Start (subprocess create failed)\n")); | |
| 450 error_info->SetReport(ERROR_SEL_LDR_CREATE_LAUNCHER, | |
| 451 "ServiceRuntime: failed to create sel_ldr launcher"); | |
| 452 return false; | |
| 453 } | |
| 454 nacl::Handle sockets[3]; | |
| 455 if (!tmp_subprocess->Start(NACL_ARRAY_SIZE(sockets), sockets)) { | |
| 456 PLUGIN_PRINTF(("ServiceRuntime::Start (start failed)\n")); | |
| 457 error_info->SetReport(ERROR_SEL_LDR_LAUNCH, | |
| 458 "ServiceRuntime: failed to start"); | |
| 459 return false; | |
| 460 } | |
| 461 | |
| 462 async_receive_desc_.reset( | |
| 463 plugin()->wrapper_factory()->MakeImcSock(sockets[1])); | |
| 464 async_send_desc_.reset(plugin()->wrapper_factory()->MakeImcSock(sockets[2])); | |
| 465 | |
| 466 subprocess_.reset(tmp_subprocess.release()); | |
| 467 if (!InitCommunication(nacl_desc, error_info)) { | |
| 468 subprocess_.reset(NULL); | |
| 469 return false; | |
| 470 } | |
| 471 | |
| 472 PLUGIN_PRINTF(("ServiceRuntime::Start (return 1)\n")); | |
| 473 return true; | |
| 474 } | |
| 475 | |
| 476 SrpcClient* ServiceRuntime::SetupAppChannel() { | |
| 477 PLUGIN_PRINTF(("ServiceRuntime::SetupAppChannel (subprocess_=%p)\n", | |
| 478 reinterpret_cast<void*>(subprocess_.get()))); | |
| 479 nacl::DescWrapper* connect_desc = subprocess_->socket_addr()->Connect(); | |
| 480 if (NULL == connect_desc) { | |
| 481 PLUGIN_PRINTF(("ServiceRuntime::SetupAppChannel (connect failed)\n")); | |
| 482 return NULL; | |
| 483 } else { | |
| 484 PLUGIN_PRINTF(("ServiceRuntime::SetupAppChannel (conect_desc=%p)\n", | |
| 485 static_cast<void*>(connect_desc))); | |
| 486 SrpcClient* srpc_client = SrpcClient::New(plugin(), connect_desc); | |
| 487 PLUGIN_PRINTF(("ServiceRuntime::SetupAppChannel (srpc_client=%p)\n", | |
| 488 static_cast<void*>(srpc_client))); | |
| 489 return srpc_client; | |
| 490 } | |
| 491 } | |
| 492 | |
| 493 bool ServiceRuntime::Kill() { | |
| 494 return subprocess_->KillChildProcess(); | |
| 495 } | |
| 496 | |
| 497 bool ServiceRuntime::Log(int severity, nacl::string msg) { | |
| 498 NaClSrpcResultCodes rpc_result = | |
| 499 NaClSrpcInvokeBySignature(&command_channel_, | |
| 500 "log:is:", | |
| 501 severity, | |
| 502 strdup(msg.c_str())); | |
| 503 return (NACL_SRPC_RESULT_OK == rpc_result); | |
| 504 } | |
| 505 | |
| 506 void ServiceRuntime::Shutdown() { | |
| 507 if (subprocess_ != NULL) { | |
| 508 Kill(); | |
| 509 } | |
| 510 rev_interface_->ShutDown(); | |
| 511 anchor_->Abandon(); | |
| 512 // Abandon callbacks, tell service threads to quit if they were | |
| 513 // blocked waiting for main thread operations to finish. Note that | |
| 514 // some callbacks must still await their completion event, e.g., | |
| 515 // CallOnMainThread must still wait for the time out, or I/O events | |
| 516 // must finish, so resources associated with pending events cannot | |
| 517 // be deallocated. | |
| 518 | |
| 519 // Note that this does waitpid() to get rid of any zombie subprocess. | |
| 520 subprocess_.reset(NULL); | |
| 521 | |
| 522 NaClSrpcDtor(&command_channel_); | |
| 523 | |
| 524 // subprocess_ killed, but threads waiting on messages from the | |
| 525 // service runtime may not have noticed yet. The low-level | |
| 526 // NaClSimpleRevService code takes care to refcount the data objects | |
| 527 // that it needs, and reverse_service_ is also refcounted. We wait | |
| 528 // for the service threads to get their EOF indications. | |
| 529 if (reverse_service_ != NULL) { | |
| 530 reverse_service_->WaitForServiceThreadsToExit(); | |
| 531 reverse_service_->Unref(); | |
| 532 reverse_service_ = NULL; | |
| 533 } | |
| 534 } | |
| 535 | |
| 536 ServiceRuntime::~ServiceRuntime() { | |
| 537 PLUGIN_PRINTF(("ServiceRuntime::~ServiceRuntime (this=%p)\n", | |
| 538 static_cast<void*>(this))); | |
| 539 // We do this just in case Shutdown() was not called. | |
| 540 subprocess_.reset(NULL); | |
| 541 if (reverse_service_ != NULL) { | |
| 542 reverse_service_->Unref(); | |
| 543 } | |
| 544 | |
| 545 rev_interface_->Unref(); | |
| 546 | |
| 547 anchor_->Unref(); | |
| 548 } | |
| 549 | |
| 550 } // namespace plugin | |
| OLD | NEW |