| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (c) 2012 The Chromium Authors. All rights reserved. | 2 * Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 3 * Use of this source code is governed by a BSD-style license that can be | 3 * Use of this source code is governed by a BSD-style license that can be |
| 4 * found in the LICENSE file. | 4 * found in the LICENSE file. |
| 5 */ | 5 */ |
| 6 | 6 |
| 7 #define NACL_LOG_MODULE_NAME "Plugin_ServiceRuntime" | 7 #define NACL_LOG_MODULE_NAME "Plugin_ServiceRuntime" |
| 8 | 8 |
| 9 #include "ppapi/native_client/src/trusted/plugin/service_runtime.h" | 9 #include "ppapi/native_client/src/trusted/plugin/service_runtime.h" |
| 10 | 10 |
| (...skipping 21 matching lines...) Expand all Loading... |
| 32 #include "ppapi/c/pp_errors.h" | 32 #include "ppapi/c/pp_errors.h" |
| 33 #include "ppapi/cpp/core.h" | 33 #include "ppapi/cpp/core.h" |
| 34 #include "ppapi/cpp/completion_callback.h" | 34 #include "ppapi/cpp/completion_callback.h" |
| 35 | 35 |
| 36 #include "ppapi/native_client/src/trusted/plugin/plugin.h" | 36 #include "ppapi/native_client/src/trusted/plugin/plugin.h" |
| 37 #include "ppapi/native_client/src/trusted/plugin/plugin_error.h" | 37 #include "ppapi/native_client/src/trusted/plugin/plugin_error.h" |
| 38 #include "ppapi/native_client/src/trusted/plugin/pnacl_resources.h" | 38 #include "ppapi/native_client/src/trusted/plugin/pnacl_resources.h" |
| 39 #include "ppapi/native_client/src/trusted/plugin/sel_ldr_launcher_chrome.h" | 39 #include "ppapi/native_client/src/trusted/plugin/sel_ldr_launcher_chrome.h" |
| 40 #include "ppapi/native_client/src/trusted/plugin/srpc_client.h" | 40 #include "ppapi/native_client/src/trusted/plugin/srpc_client.h" |
| 41 #include "ppapi/native_client/src/trusted/plugin/utility.h" | 41 #include "ppapi/native_client/src/trusted/plugin/utility.h" |
| 42 #include "ppapi/native_client/src/trusted/weak_ref/call_on_main_thread.h" | |
| 43 | 42 |
| 44 namespace plugin { | 43 namespace plugin { |
| 45 | 44 |
| 46 OpenManifestEntryResource::~OpenManifestEntryResource() { | |
| 47 } | |
| 48 | |
| 49 PluginReverseInterface::PluginReverseInterface( | |
| 50 nacl::WeakRefAnchor* anchor, | |
| 51 PP_Instance pp_instance, | |
| 52 ServiceRuntime* service_runtime) | |
| 53 : anchor_(anchor), | |
| 54 pp_instance_(pp_instance), | |
| 55 service_runtime_(service_runtime), | |
| 56 shutting_down_(false) { | |
| 57 NaClXMutexCtor(&mu_); | |
| 58 NaClXCondVarCtor(&cv_); | |
| 59 } | |
| 60 | |
| 61 PluginReverseInterface::~PluginReverseInterface() { | |
| 62 NaClCondVarDtor(&cv_); | |
| 63 NaClMutexDtor(&mu_); | |
| 64 } | |
| 65 | |
| 66 void PluginReverseInterface::ShutDown() { | |
| 67 NaClLog(4, "PluginReverseInterface::Shutdown: entered\n"); | |
| 68 nacl::MutexLocker take(&mu_); | |
| 69 shutting_down_ = true; | |
| 70 NaClXCondVarBroadcast(&cv_); | |
| 71 NaClLog(4, "PluginReverseInterface::Shutdown: broadcasted, exiting\n"); | |
| 72 } | |
| 73 | |
| 74 void PluginReverseInterface::DoPostMessage(std::string message) { | |
| 75 // This feature is no longer used. | |
| 76 // TODO(teravest): Remove this once this is gone from nacl::ReverseInterface. | |
| 77 } | |
| 78 | |
| 79 void PluginReverseInterface::StartupInitializationComplete() { | |
| 80 // This is no longer used. | |
| 81 } | |
| 82 | |
| 83 // TODO(bsy): OpenManifestEntry should use the manifest to ResolveKey | |
| 84 // and invoke StreamAsFile with a completion callback that invokes | |
| 85 // GetPOSIXFileDesc. | |
| 86 bool PluginReverseInterface::OpenManifestEntry(std::string url_key, | |
| 87 struct NaClFileInfo* info) { | |
| 88 // This method should only ever be called from the PNaCl translator, as the | |
| 89 // IRT is not available there. | |
| 90 // TODO(teravest): Remove support for OpenManifestEntry here once | |
| 91 // crbug.com/302078 is resolved. | |
| 92 if (service_runtime_->main_service_runtime()) { | |
| 93 NaClLog(LOG_ERROR, | |
| 94 "OpenManifestEntry should only be used by PNaCl translator.\n"); | |
| 95 return false; | |
| 96 } | |
| 97 | |
| 98 bool op_complete = false; // NB: mu_ and cv_ also controls access to this! | |
| 99 // The to_open object is owned by the weak ref callback. Because this function | |
| 100 // waits for the callback to finish, the to_open object will be deallocated on | |
| 101 // the main thread before this function can return. The pointers it contains | |
| 102 // to stack variables will not leak. | |
| 103 OpenManifestEntryResource* to_open = | |
| 104 new OpenManifestEntryResource(url_key, info, &op_complete); | |
| 105 CHECK(to_open != NULL); | |
| 106 NaClLog(4, "PluginReverseInterface::OpenManifestEntry: %s\n", | |
| 107 url_key.c_str()); | |
| 108 // This assumes we are not on the main thread. If false, we deadlock. | |
| 109 plugin::WeakRefCallOnMainThread( | |
| 110 anchor_, | |
| 111 0, | |
| 112 this, | |
| 113 &plugin::PluginReverseInterface::OpenManifestEntry_MainThreadContinuation, | |
| 114 to_open); | |
| 115 NaClLog(4, | |
| 116 "PluginReverseInterface::OpenManifestEntry:" | |
| 117 " waiting on main thread\n"); | |
| 118 | |
| 119 { | |
| 120 nacl::MutexLocker take(&mu_); | |
| 121 while (!shutting_down_ && !op_complete) | |
| 122 NaClXCondVarWait(&cv_, &mu_); | |
| 123 NaClLog(4, "PluginReverseInterface::OpenManifestEntry: done!\n"); | |
| 124 if (shutting_down_) { | |
| 125 NaClLog(4, | |
| 126 "PluginReverseInterface::OpenManifestEntry:" | |
| 127 " plugin is shutting down\n"); | |
| 128 return false; | |
| 129 } | |
| 130 } | |
| 131 | |
| 132 // info->desc has the returned descriptor if successful, else -1. | |
| 133 | |
| 134 // The caller is responsible for not closing info->desc. If it is | |
| 135 // closed prematurely, then another open could re-use the OS | |
| 136 // descriptor, confusing the opened_ map. If the caller is going to | |
| 137 // want to make a NaClDesc object and transfer it etc., then the | |
| 138 // caller should DUP the descriptor (but remember the original | |
| 139 // value) for use by the NaClDesc object, which closes when the | |
| 140 // object is destroyed. | |
| 141 NaClLog(4, | |
| 142 "PluginReverseInterface::OpenManifestEntry: info->desc = %d\n", | |
| 143 info->desc); | |
| 144 if (info->desc == -1) { | |
| 145 // TODO(bsy,ncbray): what else should we do with the error? This | |
| 146 // is a runtime error that may simply be a programming error in | |
| 147 // the untrusted code, or it may be something else wrong w/ the | |
| 148 // manifest. | |
| 149 NaClLog(4, "OpenManifestEntry: failed for key %s", url_key.c_str()); | |
| 150 } | |
| 151 return true; | |
| 152 } | |
| 153 | |
| 154 // Transfer point from OpenManifestEntry() which runs on the main thread | |
| 155 // (Some PPAPI actions -- like StreamAsFile -- can only run on the main thread). | |
| 156 // OpenManifestEntry() is waiting on a condvar for this continuation to | |
| 157 // complete. We Broadcast and awaken OpenManifestEntry() whenever we are done | |
| 158 // either here, or in a later MainThreadContinuation step, if there are | |
| 159 // multiple steps. | |
| 160 void PluginReverseInterface::OpenManifestEntry_MainThreadContinuation( | |
| 161 OpenManifestEntryResource* p, | |
| 162 int32_t err) { | |
| 163 UNREFERENCED_PARAMETER(err); | |
| 164 // CallOnMainThread continuations always called with err == PP_OK. | |
| 165 | |
| 166 NaClLog(4, "Entered OpenManifestEntry_MainThreadContinuation\n"); | |
| 167 | |
| 168 // Because p is owned by the callback of this invocation, so it is necessary | |
| 169 // to create another instance. | |
| 170 OpenManifestEntryResource* open_cont = new OpenManifestEntryResource(*p); | |
| 171 pp::CompletionCallback stream_cc = WeakRefNewCallback( | |
| 172 anchor_, | |
| 173 this, | |
| 174 &PluginReverseInterface::StreamAsFile_MainThreadContinuation, | |
| 175 open_cont); | |
| 176 | |
| 177 GetNaClInterface()->OpenManifestEntry( | |
| 178 pp_instance_, | |
| 179 PP_FromBool(!service_runtime_->main_service_runtime()), | |
| 180 p->url.c_str(), | |
| 181 &open_cont->pp_file_info, | |
| 182 stream_cc.pp_completion_callback()); | |
| 183 // p is deleted automatically. | |
| 184 } | |
| 185 | |
| 186 void PluginReverseInterface::StreamAsFile_MainThreadContinuation( | |
| 187 OpenManifestEntryResource* p, | |
| 188 int32_t result) { | |
| 189 NaClLog(4, "Entered StreamAsFile_MainThreadContinuation\n"); | |
| 190 { | |
| 191 nacl::MutexLocker take(&mu_); | |
| 192 if (result == PP_OK) { | |
| 193 // We downloaded this file to temporary storage for this plugin; it's | |
| 194 // reasonable to provide a file descriptor with write access. | |
| 195 p->file_info->desc = ConvertFileDescriptor(p->pp_file_info.handle, false); | |
| 196 p->file_info->file_token.lo = p->pp_file_info.token_lo; | |
| 197 p->file_info->file_token.hi = p->pp_file_info.token_hi; | |
| 198 NaClLog(4, | |
| 199 "StreamAsFile_MainThreadContinuation: PP_OK, desc %d\n", | |
| 200 p->file_info->desc); | |
| 201 } else { | |
| 202 NaClLog( | |
| 203 4, | |
| 204 "StreamAsFile_MainThreadContinuation: !PP_OK, setting desc -1\n"); | |
| 205 p->file_info->desc = -1; | |
| 206 } | |
| 207 *p->op_complete_ptr = true; | |
| 208 NaClXCondVarBroadcast(&cv_); | |
| 209 } | |
| 210 } | |
| 211 | |
| 212 void PluginReverseInterface::ReportCrash() { | |
| 213 // This is now handled through Chromium IPC. | |
| 214 } | |
| 215 | |
| 216 void PluginReverseInterface::ReportExitStatus(int exit_status) { | |
| 217 // We do nothing here; reporting exit status is handled through a separate | |
| 218 // embedder interface. | |
| 219 } | |
| 220 | |
| 221 int64_t PluginReverseInterface::RequestQuotaForWrite( | |
| 222 std::string file_id, int64_t offset, int64_t bytes_to_write) { | |
| 223 return bytes_to_write; | |
| 224 } | |
| 225 | |
| 226 ServiceRuntime::ServiceRuntime(Plugin* plugin, | 45 ServiceRuntime::ServiceRuntime(Plugin* plugin, |
| 227 PP_Instance pp_instance, | 46 PP_Instance pp_instance, |
| 228 bool main_service_runtime, | 47 bool main_service_runtime, |
| 229 bool uses_nonsfi_mode) | 48 bool uses_nonsfi_mode) |
| 230 : plugin_(plugin), | 49 : plugin_(plugin), |
| 231 pp_instance_(pp_instance), | 50 pp_instance_(pp_instance), |
| 232 main_service_runtime_(main_service_runtime), | 51 main_service_runtime_(main_service_runtime), |
| 233 uses_nonsfi_mode_(uses_nonsfi_mode), | 52 uses_nonsfi_mode_(uses_nonsfi_mode), |
| 234 reverse_service_(NULL), | |
| 235 anchor_(new nacl::WeakRefAnchor()), | |
| 236 rev_interface_(new PluginReverseInterface(anchor_, pp_instance, this)), | |
| 237 start_sel_ldr_done_(false), | 53 start_sel_ldr_done_(false), |
| 238 sel_ldr_wait_timed_out_(false), | 54 sel_ldr_wait_timed_out_(false), |
| 239 start_nexe_done_(false), | 55 start_nexe_done_(false), |
| 240 nexe_started_ok_(false), | 56 nexe_started_ok_(false), |
| 241 bootstrap_channel_(NACL_INVALID_HANDLE) { | 57 bootstrap_channel_(NACL_INVALID_HANDLE) { |
| 242 NaClSrpcChannelInitialize(&command_channel_); | 58 NaClSrpcChannelInitialize(&command_channel_); |
| 243 NaClXMutexCtor(&mu_); | 59 NaClXMutexCtor(&mu_); |
| 244 NaClXCondVarCtor(&cond_); | 60 NaClXCondVarCtor(&cond_); |
| 245 } | 61 } |
| 246 | 62 |
| (...skipping 13 matching lines...) Expand all Loading... |
| 260 if (!subprocess_->SetupCommand(&command_channel_)) { | 76 if (!subprocess_->SetupCommand(&command_channel_)) { |
| 261 ErrorInfo error_info; | 77 ErrorInfo error_info; |
| 262 error_info.SetReport(PP_NACL_ERROR_SEL_LDR_COMMUNICATION_CMD_CHANNEL, | 78 error_info.SetReport(PP_NACL_ERROR_SEL_LDR_COMMUNICATION_CMD_CHANNEL, |
| 263 "ServiceRuntime: command channel creation failed"); | 79 "ServiceRuntime: command channel creation failed"); |
| 264 ReportLoadError(error_info); | 80 ReportLoadError(error_info); |
| 265 return false; | 81 return false; |
| 266 } | 82 } |
| 267 return true; | 83 return true; |
| 268 } | 84 } |
| 269 | 85 |
| 270 bool ServiceRuntime::InitReverseService() { | |
| 271 if (uses_nonsfi_mode_) { | |
| 272 // In non-SFI mode, no reverse service is set up. Just returns success. | |
| 273 return true; | |
| 274 } | |
| 275 | |
| 276 // Hook up the reverse service channel. We are the IMC client, but | |
| 277 // provide SRPC service. | |
| 278 NaClDesc* out_conn_cap; | |
| 279 NaClSrpcResultCodes rpc_result = | |
| 280 NaClSrpcInvokeBySignature(&command_channel_, | |
| 281 "reverse_setup::h", | |
| 282 &out_conn_cap); | |
| 283 | |
| 284 if (NACL_SRPC_RESULT_OK != rpc_result) { | |
| 285 ErrorInfo error_info; | |
| 286 error_info.SetReport(PP_NACL_ERROR_SEL_LDR_COMMUNICATION_REV_SETUP, | |
| 287 "ServiceRuntime: reverse setup rpc failed"); | |
| 288 ReportLoadError(error_info); | |
| 289 return false; | |
| 290 } | |
| 291 // Get connection capability to service runtime where the IMC | |
| 292 // server/SRPC client is waiting for a rendezvous. | |
| 293 NaClLog(4, "ServiceRuntime: got 0x%" NACL_PRIxPTR "\n", | |
| 294 (uintptr_t) out_conn_cap); | |
| 295 nacl::DescWrapper* conn_cap = plugin_->wrapper_factory()->MakeGenericCleanup( | |
| 296 out_conn_cap); | |
| 297 if (conn_cap == NULL) { | |
| 298 ErrorInfo error_info; | |
| 299 error_info.SetReport(PP_NACL_ERROR_SEL_LDR_COMMUNICATION_WRAPPER, | |
| 300 "ServiceRuntime: wrapper allocation failure"); | |
| 301 ReportLoadError(error_info); | |
| 302 return false; | |
| 303 } | |
| 304 out_conn_cap = NULL; // ownership passed | |
| 305 NaClLog(4, "ServiceRuntime::InitReverseService: starting reverse service\n"); | |
| 306 reverse_service_ = new nacl::ReverseService(conn_cap, rev_interface_->Ref()); | |
| 307 if (!reverse_service_->Start()) { | |
| 308 ErrorInfo error_info; | |
| 309 error_info.SetReport(PP_NACL_ERROR_SEL_LDR_COMMUNICATION_REV_SERVICE, | |
| 310 "ServiceRuntime: starting reverse services failed"); | |
| 311 ReportLoadError(error_info); | |
| 312 return false; | |
| 313 } | |
| 314 return true; | |
| 315 } | |
| 316 | |
| 317 bool ServiceRuntime::StartModule() { | 86 bool ServiceRuntime::StartModule() { |
| 318 // start the module. otherwise we cannot connect for multimedia | 87 // start the module. otherwise we cannot connect for multimedia |
| 319 // subsystem since that is handled by user-level code (not secure!) | 88 // subsystem since that is handled by user-level code (not secure!) |
| 320 // in libsrpc. | 89 // in libsrpc. |
| 321 int load_status = -1; | 90 int load_status = -1; |
| 322 if (uses_nonsfi_mode_) { | 91 if (uses_nonsfi_mode_) { |
| 323 // In non-SFI mode, we don't need to call start_module SRPC to launch | 92 // In non-SFI mode, we don't need to call start_module SRPC to launch |
| 324 // the plugin. | 93 // the plugin. |
| 325 load_status = LOAD_OK; | 94 load_status = LOAD_OK; |
| 326 } else { | 95 } else { |
| (...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 452 ReapLogs(); | 221 ReapLogs(); |
| 453 } | 222 } |
| 454 // This only matters if a background thread is waiting, but we signal in all | 223 // This only matters if a background thread is waiting, but we signal in all |
| 455 // cases to simplify the code. | 224 // cases to simplify the code. |
| 456 SignalNexeStarted(ok); | 225 SignalNexeStarted(ok); |
| 457 } | 226 } |
| 458 | 227 |
| 459 bool ServiceRuntime::StartNexeInternal() { | 228 bool ServiceRuntime::StartNexeInternal() { |
| 460 if (!SetupCommandChannel()) | 229 if (!SetupCommandChannel()) |
| 461 return false; | 230 return false; |
| 462 if (!InitReverseService()) | |
| 463 return false; | |
| 464 return StartModule(); | 231 return StartModule(); |
| 465 } | 232 } |
| 466 | 233 |
| 467 void ServiceRuntime::ReapLogs() { | 234 void ServiceRuntime::ReapLogs() { |
| 468 // TODO(teravest): We should allow the NaCl process to crash itself when a | 235 // TODO(teravest): We should allow the NaCl process to crash itself when a |
| 469 // module fails to start, and remove the call to RemoteLog() here. The | 236 // module fails to start, and remove the call to RemoteLog() here. The |
| 470 // reverse channel is no longer needed for crash reporting. | 237 // reverse channel is no longer needed for crash reporting. |
| 471 // | 238 // |
| 472 // The reasoning behind the current code behavior follows: | 239 // The reasoning behind the current code behavior follows: |
| 473 // On a load failure the NaCl process does not crash itself to | 240 // On a load failure the NaCl process does not crash itself to |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 509 bool ServiceRuntime::RemoteLog(int severity, const std::string& msg) { | 276 bool ServiceRuntime::RemoteLog(int severity, const std::string& msg) { |
| 510 NaClSrpcResultCodes rpc_result = | 277 NaClSrpcResultCodes rpc_result = |
| 511 NaClSrpcInvokeBySignature(&command_channel_, | 278 NaClSrpcInvokeBySignature(&command_channel_, |
| 512 "log:is:", | 279 "log:is:", |
| 513 severity, | 280 severity, |
| 514 strdup(msg.c_str())); | 281 strdup(msg.c_str())); |
| 515 return (NACL_SRPC_RESULT_OK == rpc_result); | 282 return (NACL_SRPC_RESULT_OK == rpc_result); |
| 516 } | 283 } |
| 517 | 284 |
| 518 void ServiceRuntime::Shutdown() { | 285 void ServiceRuntime::Shutdown() { |
| 519 rev_interface_->ShutDown(); | |
| 520 anchor_->Abandon(); | |
| 521 // Abandon callbacks, tell service threads to quit if they were | 286 // Abandon callbacks, tell service threads to quit if they were |
| 522 // blocked waiting for main thread operations to finish. Note that | 287 // blocked waiting for main thread operations to finish. Note that |
| 523 // some callbacks must still await their completion event, e.g., | 288 // some callbacks must still await their completion event, e.g., |
| 524 // CallOnMainThread must still wait for the time out, or I/O events | 289 // CallOnMainThread must still wait for the time out, or I/O events |
| 525 // must finish, so resources associated with pending events cannot | 290 // must finish, so resources associated with pending events cannot |
| 526 // be deallocated. | 291 // be deallocated. |
| 527 | 292 |
| 528 // Note that this does waitpid() to get rid of any zombie subprocess. | 293 // Note that this does waitpid() to get rid of any zombie subprocess. |
| 529 subprocess_.reset(NULL); | 294 subprocess_.reset(NULL); |
| 530 | 295 |
| 531 NaClSrpcDtor(&command_channel_); | 296 NaClSrpcDtor(&command_channel_); |
| 532 | |
| 533 // subprocess_ has been shut down, but threads waiting on messages | |
| 534 // from the service runtime may not have noticed yet. The low-level | |
| 535 // NaClSimpleRevService code takes care to refcount the data objects | |
| 536 // that it needs, and reverse_service_ is also refcounted. We wait | |
| 537 // for the service threads to get their EOF indications. | |
| 538 if (reverse_service_ != NULL) { | |
| 539 reverse_service_->WaitForServiceThreadsToExit(); | |
| 540 reverse_service_->Unref(); | |
| 541 reverse_service_ = NULL; | |
| 542 } | |
| 543 } | 297 } |
| 544 | 298 |
| 545 ServiceRuntime::~ServiceRuntime() { | 299 ServiceRuntime::~ServiceRuntime() { |
| 546 NaClLog(4, "ServiceRuntime::~ServiceRuntime (this=%p)\n", | 300 NaClLog(4, "ServiceRuntime::~ServiceRuntime (this=%p)\n", |
| 547 static_cast<void*>(this)); | 301 static_cast<void*>(this)); |
| 548 // We do this just in case Shutdown() was not called. | 302 // We do this just in case Shutdown() was not called. |
| 549 subprocess_.reset(NULL); | 303 subprocess_.reset(NULL); |
| 550 if (reverse_service_ != NULL) | |
| 551 reverse_service_->Unref(); | |
| 552 | 304 |
| 553 rev_interface_->Unref(); | |
| 554 | |
| 555 anchor_->Unref(); | |
| 556 NaClCondVarDtor(&cond_); | 305 NaClCondVarDtor(&cond_); |
| 557 NaClMutexDtor(&mu_); | 306 NaClMutexDtor(&mu_); |
| 558 } | 307 } |
| 559 | 308 |
| 560 } // namespace plugin | 309 } // namespace plugin |
| OLD | NEW |