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 |