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

Side by Side Diff: ppapi/native_client/src/trusted/plugin/plugin.cc

Issue 876483002: NaCl: Move src/trusted/plugin/ to components/nacl/renderer/plugin/ (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Update #include guards Created 5 years, 10 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
OLDNEW
(Empty)
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "ppapi/native_client/src/trusted/plugin/plugin.h"
6
7 #include <sys/stat.h>
8 #include <sys/types.h>
9
10 #include <string>
11
12 #include "native_client/src/include/nacl_base.h"
13 #include "native_client/src/include/nacl_macros.h"
14 #include "native_client/src/include/nacl_scoped_ptr.h"
15 #include "native_client/src/include/portability.h"
16 #include "native_client/src/include/portability_io.h"
17 #include "native_client/src/shared/platform/nacl_check.h"
18 #include "native_client/src/trusted/desc/nacl_desc_wrapper.h"
19
20 #include "ppapi/c/pp_errors.h"
21 #include "ppapi/c/private/ppb_nacl_private.h"
22 #include "ppapi/cpp/module.h"
23
24 #include "ppapi/native_client/src/trusted/plugin/nacl_subprocess.h"
25 #include "ppapi/native_client/src/trusted/plugin/plugin_error.h"
26 #include "ppapi/native_client/src/trusted/plugin/service_runtime.h"
27 #include "ppapi/native_client/src/trusted/plugin/utility.h"
28
29 namespace plugin {
30
31 namespace {
32
33 // Up to 20 seconds
34 const int64_t kTimeSmallMin = 1; // in ms
35 const int64_t kTimeSmallMax = 20000; // in ms
36 const uint32_t kTimeSmallBuckets = 100;
37
38 } // namespace
39
40 void Plugin::ShutDownSubprocesses() {
41 PLUGIN_PRINTF(("Plugin::ShutDownSubprocesses (this=%p)\n",
42 static_cast<void*>(this)));
43
44 // Shut down service runtime. This must be done before all other calls so
45 // they don't block forever when waiting for the upcall thread to exit.
46 main_subprocess_.Shutdown();
47
48 PLUGIN_PRINTF(("Plugin::ShutDownSubprocess (this=%p, return)\n",
49 static_cast<void*>(this)));
50 }
51
52 void Plugin::HistogramTimeSmall(const std::string& name,
53 int64_t ms) {
54 if (ms < 0) return;
55 uma_interface_.HistogramCustomTimes(name,
56 ms,
57 kTimeSmallMin, kTimeSmallMax,
58 kTimeSmallBuckets);
59 }
60
61 bool Plugin::LoadHelperNaClModuleInternal(NaClSubprocess* subprocess,
62 const SelLdrStartParams& params) {
63 CHECK(!pp::Module::Get()->core()->IsMainThread());
64 ServiceRuntime* service_runtime =
65 new ServiceRuntime(this,
66 pp_instance(),
67 false, // No main_service_runtime.
68 false); // No non-SFI mode (i.e. in SFI-mode).
69
70 // Now start the SelLdr instance. This must be created on the main thread.
71 bool service_runtime_started = false;
72 pp::CompletionCallback sel_ldr_callback =
73 callback_factory_.NewCallback(&Plugin::SignalStartSelLdrDone,
74 &service_runtime_started,
75 service_runtime);
76 pp::CompletionCallback callback =
77 callback_factory_.NewCallback(&Plugin::StartSelLdrOnMainThread,
78 service_runtime, params,
79 sel_ldr_callback);
80 pp::Module::Get()->core()->CallOnMainThread(0, callback, 0);
81 if (!service_runtime->WaitForSelLdrStart()) {
82 PLUGIN_PRINTF(("Plugin::LoadHelperNaClModule "
83 "WaitForSelLdrStart timed out!\n"));
84 service_runtime->Shutdown();
85 // Don't delete service_runtime here; it could still be used by the pending
86 // SignalStartSelLdrDone callback.
87 return false;
88 }
89 PLUGIN_PRINTF(("Plugin::LoadHelperNaClModule (service_runtime_started=%d)\n",
90 service_runtime_started));
91 if (!service_runtime_started) {
92 service_runtime->Shutdown();
93 delete service_runtime;
94 return false;
95 }
96
97 // Now actually start the nexe.
98 //
99 // We can't use pp::BlockUntilComplete() inside an in-process plugin, so we
100 // have to roll our own blocking logic, similar to WaitForSelLdrStart()
101 // above, except without timeout logic.
102 pp::Module::Get()->core()->CallOnMainThread(
103 0,
104 callback_factory_.NewCallback(&Plugin::StartNexe, service_runtime));
105 if (!service_runtime->WaitForNexeStart()) {
106 service_runtime->Shutdown();
107 delete service_runtime;
108 return false;
109 }
110 subprocess->set_service_runtime(service_runtime);
111 return true;
112 }
113
114 void Plugin::StartSelLdrOnMainThread(int32_t pp_error,
115 ServiceRuntime* service_runtime,
116 const SelLdrStartParams& params,
117 pp::CompletionCallback callback) {
118 CHECK(pp_error == PP_OK);
119 service_runtime->StartSelLdr(params, callback);
120 }
121
122 void Plugin::SignalStartSelLdrDone(int32_t pp_error,
123 bool* started,
124 ServiceRuntime* service_runtime) {
125 if (service_runtime->SelLdrWaitTimedOut()) {
126 delete service_runtime;
127 } else {
128 *started = (pp_error == PP_OK);
129 service_runtime->SignalStartSelLdrDone();
130 }
131 }
132
133 void Plugin::LoadNaClModule(PP_NaClFileInfo file_info,
134 bool uses_nonsfi_mode,
135 PP_NaClAppProcessType process_type) {
136 CHECK(pp::Module::Get()->core()->IsMainThread());
137 // Before forking a new sel_ldr process, ensure that we do not leak
138 // the ServiceRuntime object for an existing subprocess, and that any
139 // associated listener threads do not go unjoined because if they
140 // outlive the Plugin object, they will not be memory safe.
141 ShutDownSubprocesses();
142 pp::Var manifest_base_url =
143 pp::Var(pp::PASS_REF, nacl_interface_->GetManifestBaseURL(pp_instance()));
144 std::string manifest_base_url_str = manifest_base_url.AsString();
145
146 SelLdrStartParams params(manifest_base_url_str,
147 file_info,
148 process_type);
149 ErrorInfo error_info;
150 ServiceRuntime* service_runtime = new ServiceRuntime(
151 this, pp_instance(), true, uses_nonsfi_mode);
152 main_subprocess_.set_service_runtime(service_runtime);
153 if (NULL == service_runtime) {
154 error_info.SetReport(
155 PP_NACL_ERROR_SEL_LDR_INIT,
156 "sel_ldr init failure " + main_subprocess_.description());
157 ReportLoadError(error_info);
158 return;
159 }
160
161 // We don't take any action once nexe loading has completed, so pass an empty
162 // callback here for |callback|.
163 pp::CompletionCallback callback = callback_factory_.NewCallback(
164 &Plugin::StartNexe, service_runtime);
165 StartSelLdrOnMainThread(
166 static_cast<int32_t>(PP_OK), service_runtime, params, callback);
167 }
168
169 void Plugin::StartNexe(int32_t pp_error, ServiceRuntime* service_runtime) {
170 CHECK(pp::Module::Get()->core()->IsMainThread());
171 if (pp_error != PP_OK)
172 return;
173 service_runtime->StartNexe();
174 }
175
176 NaClSubprocess* Plugin::LoadHelperNaClModule(const std::string& helper_url,
177 PP_NaClFileInfo file_info,
178 ErrorInfo* error_info) {
179 nacl::scoped_ptr<NaClSubprocess> nacl_subprocess(
180 new NaClSubprocess("helper module", NULL, NULL));
181 if (NULL == nacl_subprocess.get()) {
182 error_info->SetReport(PP_NACL_ERROR_SEL_LDR_INIT,
183 "unable to allocate helper subprocess.");
184 return NULL;
185 }
186
187 // Do not report UMA stats for translator-related nexes.
188 // TODO(sehr): define new UMA stats for translator related nexe events.
189 // NOTE: The PNaCl translator nexes are not built to use the IRT. This is
190 // done to save on address space and swap space.
191 SelLdrStartParams params(helper_url,
192 file_info,
193 PP_PNACL_TRANSLATOR_PROCESS_TYPE);
194
195 // Helper NaCl modules always use the PNaCl manifest, as there is no
196 // corresponding NMF.
197 if (!LoadHelperNaClModuleInternal(nacl_subprocess.get(), params))
198 return NULL;
199
200 // We can block here in StartSrpcServices, since helper NaCl
201 // modules are spawned from a private thread.
202 //
203 // TODO(bsy): if helper module crashes, we should abort.
204 // crash_cb is not used here, so we are relying on crashes
205 // being detected in StartSrpcServices or later.
206 //
207 // NB: More refactoring might be needed, however, if helper
208 // NaCl modules have their own manifest. Currently the
209 // manifest is a per-plugin-instance object, not a per
210 // NaClSubprocess object.
211 if (!nacl_subprocess->StartSrpcServices()) {
212 error_info->SetReport(PP_NACL_ERROR_SRPC_CONNECTION_FAIL,
213 "SRPC connection failure for " +
214 nacl_subprocess->description());
215 return NULL;
216 }
217
218 PLUGIN_PRINTF(("Plugin::LoadHelperNaClModule (%s, %s)\n",
219 helper_url.c_str(),
220 nacl_subprocess.get()->detailed_description().c_str()));
221
222 return nacl_subprocess.release();
223 }
224
225 // All failures of this function will show up as "Missing Plugin-in", so
226 // there is no need to log to JS console that there was an initialization
227 // failure. Note that module loading functions will log their own errors.
228 bool Plugin::Init(uint32_t argc, const char* argn[], const char* argv[]) {
229 nacl_interface_->InitializePlugin(pp_instance(), argc, argn, argv);
230 wrapper_factory_ = new nacl::DescWrapperFactory();
231 pp::CompletionCallback open_cb =
232 callback_factory_.NewCallback(&Plugin::NaClManifestFileDidOpen);
233 nacl_interface_->RequestNaClManifest(pp_instance(),
234 open_cb.pp_completion_callback());
235 return true;
236 }
237
238 Plugin::Plugin(PP_Instance pp_instance)
239 : pp::Instance(pp_instance),
240 main_subprocess_("main subprocess", NULL, NULL),
241 uses_nonsfi_mode_(false),
242 wrapper_factory_(NULL),
243 nacl_interface_(NULL),
244 uma_interface_(this) {
245 callback_factory_.Initialize(this);
246 nacl_interface_ = GetNaClInterface();
247 CHECK(nacl_interface_ != NULL);
248
249 // Notify PPB_NaCl_Private that the instance is created before altering any
250 // state that it tracks.
251 nacl_interface_->InstanceCreated(pp_instance);
252 nexe_file_info_ = kInvalidNaClFileInfo;
253 }
254
255 Plugin::~Plugin() {
256 int64_t shutdown_start = NaClGetTimeOfDayMicroseconds();
257
258 // Destroy the coordinator while the rest of the data is still there
259 pnacl_coordinator_.reset(NULL);
260
261 nacl_interface_->InstanceDestroyed(pp_instance());
262
263 // ShutDownSubprocesses shuts down the main subprocess, which shuts
264 // down the main ServiceRuntime object, which kills the subprocess.
265 // As a side effect of the subprocess being killed, the reverse
266 // services thread(s) will get EOF on the reverse channel(s), and
267 // the thread(s) will exit. In ServiceRuntime::Shutdown, we invoke
268 // ReverseService::WaitForServiceThreadsToExit(), so that there will
269 // not be an extent thread(s) hanging around. This means that the
270 // ~Plugin will block until this happens. This is a requirement,
271 // since the renderer should be free to unload the plugin code, and
272 // we cannot have threads running code that gets unloaded before
273 // they exit.
274 //
275 // By waiting for the threads here, we also ensure that the Plugin
276 // object and the subprocess and ServiceRuntime objects is not
277 // (fully) destroyed while the threads are running, so resources
278 // that are destroyed after ShutDownSubprocesses (below) are
279 // guaranteed to be live and valid for access from the service
280 // threads.
281 //
282 // The main_subprocess object, which wraps the main service_runtime
283 // object, is dtor'd implicitly after the explicit code below runs,
284 // so the main service runtime object will not have been dtor'd,
285 // though the Shutdown method may have been called, during the
286 // lifetime of the service threads.
287 ShutDownSubprocesses();
288
289 delete wrapper_factory_;
290
291 HistogramTimeSmall(
292 "NaCl.Perf.ShutdownTime.Total",
293 (NaClGetTimeOfDayMicroseconds() - shutdown_start)
294 / NACL_MICROS_PER_MILLI);
295 }
296
297 bool Plugin::HandleDocumentLoad(const pp::URLLoader& url_loader) {
298 // We don't know if the plugin will handle the document load, but return
299 // true in order to give it a chance to respond once the proxy is started.
300 return true;
301 }
302
303 void Plugin::NexeFileDidOpen(int32_t pp_error) {
304 if (pp_error != PP_OK)
305 return;
306 LoadNaClModule(
307 nexe_file_info_,
308 uses_nonsfi_mode_,
309 PP_NATIVE_NACL_PROCESS_TYPE);
310 }
311
312 void Plugin::BitcodeDidTranslate(int32_t pp_error) {
313 PLUGIN_PRINTF(("Plugin::BitcodeDidTranslate (pp_error=%" NACL_PRId32 ")\n",
314 pp_error));
315 if (pp_error != PP_OK) {
316 // Error should have been reported by pnacl. Just return.
317 return;
318 }
319
320 // Inform JavaScript that we successfully translated the bitcode to a nexe.
321 PP_FileHandle handle = pnacl_coordinator_->TakeTranslatedFileHandle();
322
323 PP_NaClFileInfo info;
324 info.handle = handle;
325 info.token_lo = 0;
326 info.token_hi = 0;
327 LoadNaClModule(
328 info,
329 false, /* uses_nonsfi_mode */
330 PP_PNACL_PROCESS_TYPE);
331 }
332
333 void Plugin::NaClManifestFileDidOpen(int32_t pp_error) {
334 PLUGIN_PRINTF(("Plugin::NaClManifestFileDidOpen (pp_error=%"
335 NACL_PRId32 ")\n", pp_error));
336 if (pp_error != PP_OK)
337 return;
338
339 PP_Var pp_program_url;
340 PP_PNaClOptions pnacl_options = {PP_FALSE, PP_FALSE, 2};
341 PP_Bool uses_nonsfi_mode;
342 if (nacl_interface_->GetManifestProgramURL(
343 pp_instance(), &pp_program_url, &pnacl_options, &uses_nonsfi_mode)) {
344 std::string program_url = pp::Var(pp::PASS_REF, pp_program_url).AsString();
345 // TODO(teravest): Make ProcessNaClManifest take responsibility for more of
346 // this function.
347 nacl_interface_->ProcessNaClManifest(pp_instance(), program_url.c_str());
348 uses_nonsfi_mode_ = PP_ToBool(uses_nonsfi_mode);
349 if (pnacl_options.translate) {
350 pp::CompletionCallback translate_callback =
351 callback_factory_.NewCallback(&Plugin::BitcodeDidTranslate);
352 pnacl_coordinator_.reset(
353 PnaclCoordinator::BitcodeToNative(this,
354 program_url,
355 pnacl_options,
356 translate_callback));
357 return;
358 } else {
359 pp::CompletionCallback open_callback =
360 callback_factory_.NewCallback(&Plugin::NexeFileDidOpen);
361 // Will always call the callback on success or failure.
362 nacl_interface_->DownloadNexe(pp_instance(),
363 program_url.c_str(),
364 &nexe_file_info_,
365 open_callback.pp_completion_callback());
366 return;
367 }
368 }
369 }
370
371 void Plugin::ReportLoadError(const ErrorInfo& error_info) {
372 nacl_interface_->ReportLoadError(pp_instance(),
373 error_info.error_code(),
374 error_info.message().c_str());
375 }
376
377 } // namespace plugin
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698