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

Side by Side Diff: src/trusted/plugin/service_runtime.cc

Issue 7799028: Remove src/trusted/plugin (Closed) Base URL: svn://svn.chromium.org/native_client/trunk/src/native_client
Patch Set: fix gyp file for necessary -I 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
« no previous file with comments | « src/trusted/plugin/service_runtime.h ('k') | src/trusted/plugin/srpc_client.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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
OLDNEW
« no previous file with comments | « src/trusted/plugin/service_runtime.h ('k') | src/trusted/plugin/srpc_client.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698