Update V8 to version 4.6.52.
[chromium-blink-merge.git] / components / nacl / renderer / plugin / plugin.cc
bloba790696f5a1baf5b843d86cf4afbff8ba0c8e79d
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.
5 #include "components/nacl/renderer/plugin/plugin.h"
7 #include <sys/stat.h>
8 #include <sys/types.h>
10 #include <string>
12 #include "components/nacl/renderer/plugin/nacl_subprocess.h"
13 #include "components/nacl/renderer/plugin/plugin_error.h"
14 #include "components/nacl/renderer/plugin/service_runtime.h"
15 #include "components/nacl/renderer/plugin/utility.h"
16 #include "components/nacl/renderer/ppb_nacl_private.h"
17 #include "native_client/src/include/nacl_base.h"
18 #include "native_client/src/include/nacl_macros.h"
19 #include "native_client/src/include/nacl_scoped_ptr.h"
20 #include "native_client/src/include/portability.h"
21 #include "native_client/src/include/portability_io.h"
22 #include "native_client/src/shared/platform/nacl_check.h"
23 #include "native_client/src/trusted/desc/nacl_desc_wrapper.h"
24 #include "ppapi/c/pp_errors.h"
25 #include "ppapi/cpp/module.h"
27 namespace plugin {
29 void Plugin::ShutDownSubprocesses() {
30 PLUGIN_PRINTF(("Plugin::ShutDownSubprocesses (this=%p)\n",
31 static_cast<void*>(this)));
33 // Shut down service runtime. This must be done before all other calls so
34 // they don't block forever when waiting for the upcall thread to exit.
35 main_subprocess_.Shutdown();
37 PLUGIN_PRINTF(("Plugin::ShutDownSubprocess (this=%p, return)\n",
38 static_cast<void*>(this)));
41 void Plugin::StartSelLdr(ServiceRuntime* service_runtime,
42 const SelLdrStartParams& params,
43 pp::CompletionCallback callback) {
44 service_runtime->StartSelLdr(params, callback);
47 void Plugin::LoadNaClModule(PP_NaClFileInfo file_info,
48 bool uses_nonsfi_mode,
49 PP_NaClAppProcessType process_type) {
50 CHECK(pp::Module::Get()->core()->IsMainThread());
51 // Before forking a new sel_ldr process, ensure that we do not leak
52 // the ServiceRuntime object for an existing subprocess, and that any
53 // associated listener threads do not go unjoined because if they
54 // outlive the Plugin object, they will not be memory safe.
55 ShutDownSubprocesses();
56 pp::Var manifest_base_url =
57 pp::Var(pp::PASS_REF, nacl_interface_->GetManifestBaseURL(pp_instance()));
58 std::string manifest_base_url_str = manifest_base_url.AsString();
60 SelLdrStartParams params(manifest_base_url_str,
61 file_info,
62 process_type);
63 ErrorInfo error_info;
64 ServiceRuntime* service_runtime = new ServiceRuntime(
65 this, pp_instance(), true, uses_nonsfi_mode);
66 main_subprocess_.set_service_runtime(service_runtime);
67 if (NULL == service_runtime) {
68 error_info.SetReport(
69 PP_NACL_ERROR_SEL_LDR_INIT,
70 "sel_ldr init failure " + main_subprocess_.description());
71 ReportLoadError(error_info);
72 return;
75 // We don't take any action once nexe loading has completed, so pass an empty
76 // callback here for |callback|.
77 pp::CompletionCallback callback = callback_factory_.NewCallback(
78 &Plugin::StartNexe, service_runtime);
79 StartSelLdr(service_runtime, params, callback);
82 void Plugin::StartNexe(int32_t pp_error, ServiceRuntime* service_runtime) {
83 CHECK(pp::Module::Get()->core()->IsMainThread());
84 if (pp_error != PP_OK)
85 return;
86 service_runtime->StartNexe();
89 void Plugin::LoadHelperNaClModule(const std::string& helper_url,
90 PP_NaClFileInfo file_info,
91 NaClSubprocess* subprocess_to_init,
92 pp::CompletionCallback callback) {
93 CHECK(pp::Module::Get()->core()->IsMainThread());
94 // Do not report UMA stats for translator-related nexes.
95 // TODO(sehr): define new UMA stats for translator related nexe events.
96 SelLdrStartParams params(helper_url,
97 file_info,
98 PP_PNACL_TRANSLATOR_PROCESS_TYPE);
99 ServiceRuntime* service_runtime =
100 new ServiceRuntime(this, pp_instance(),
101 false, // Not main_service_runtime.
102 false); // No non-SFI mode (i.e. in SFI-mode).
103 subprocess_to_init->set_service_runtime(service_runtime);
104 pp::CompletionCallback sel_ldr_callback = callback_factory_.NewCallback(
105 &Plugin::StartHelperNexe, subprocess_to_init, callback);
106 StartSelLdr(service_runtime, params, sel_ldr_callback);
109 void Plugin::StartHelperNexe(int32_t pp_error,
110 NaClSubprocess* subprocess_to_init,
111 pp::CompletionCallback callback) {
112 CHECK(pp::Module::Get()->core()->IsMainThread());
113 if (pp_error != PP_OK) {
114 callback.RunAndClear(pp_error);
115 return;
117 // TODO(jvoung): This operation blocks. That's bad because this is the
118 // main thread. However, we could make it so that StartHelperNexe isn't
119 // called until the blocking is minimized. There is a hook in
120 // sel_main_chrome which indicates when the nexe load is done. If we hook
121 // up that hook to StartSelLdr's callback, then we'll only
122 // call StartNexe once the nexe load is done instead of blocking here
123 // until the nexe load is done.
124 subprocess_to_init->service_runtime()->StartNexe();
125 callback.RunAndClear(PP_OK);
128 // All failures of this function will show up as "Missing Plugin-in", so
129 // there is no need to log to JS console that there was an initialization
130 // failure. Note that module loading functions will log their own errors.
131 bool Plugin::Init(uint32_t argc, const char* argn[], const char* argv[]) {
132 nacl_interface_->InitializePlugin(pp_instance(), argc, argn, argv);
133 wrapper_factory_ = new nacl::DescWrapperFactory();
134 pp::CompletionCallback open_cb =
135 callback_factory_.NewCallback(&Plugin::NaClManifestFileDidOpen);
136 nacl_interface_->RequestNaClManifest(pp_instance(),
137 open_cb.pp_completion_callback());
138 return true;
141 Plugin::Plugin(PP_Instance pp_instance)
142 : pp::Instance(pp_instance),
143 main_subprocess_("main subprocess", NULL, NULL),
144 uses_nonsfi_mode_(false),
145 wrapper_factory_(NULL),
146 nacl_interface_(NULL),
147 uma_interface_(this) {
148 callback_factory_.Initialize(this);
149 nacl_interface_ = GetNaClInterface();
150 CHECK(nacl_interface_ != NULL);
152 // Notify PPB_NaCl_Private that the instance is created before altering any
153 // state that it tracks.
154 nacl_interface_->InstanceCreated(pp_instance);
155 nexe_file_info_ = kInvalidNaClFileInfo;
158 Plugin::~Plugin() {
159 // Destroy the coordinator while the rest of the data is still there
160 pnacl_coordinator_.reset(NULL);
162 nacl_interface_->InstanceDestroyed(pp_instance());
164 // ShutDownSubprocesses shuts down the main subprocess, which shuts
165 // down the main ServiceRuntime object, which kills the subprocess.
166 // As a side effect of the subprocess being killed, the reverse
167 // services thread(s) will get EOF on the reverse channel(s), and
168 // the thread(s) will exit. In ServiceRuntime::Shutdown, we invoke
169 // ReverseService::WaitForServiceThreadsToExit(), so that there will
170 // not be an extent thread(s) hanging around. This means that the
171 // ~Plugin will block until this happens. This is a requirement,
172 // since the renderer should be free to unload the plugin code, and
173 // we cannot have threads running code that gets unloaded before
174 // they exit.
176 // By waiting for the threads here, we also ensure that the Plugin
177 // object and the subprocess and ServiceRuntime objects is not
178 // (fully) destroyed while the threads are running, so resources
179 // that are destroyed after ShutDownSubprocesses (below) are
180 // guaranteed to be live and valid for access from the service
181 // threads.
183 // The main_subprocess object, which wraps the main service_runtime
184 // object, is dtor'd implicitly after the explicit code below runs,
185 // so the main service runtime object will not have been dtor'd,
186 // though the Shutdown method may have been called, during the
187 // lifetime of the service threads.
188 ShutDownSubprocesses();
190 delete wrapper_factory_;
193 bool Plugin::HandleDocumentLoad(const pp::URLLoader& url_loader) {
194 // We don't know if the plugin will handle the document load, but return
195 // true in order to give it a chance to respond once the proxy is started.
196 return true;
199 void Plugin::NexeFileDidOpen(int32_t pp_error) {
200 if (pp_error != PP_OK)
201 return;
202 LoadNaClModule(
203 nexe_file_info_,
204 uses_nonsfi_mode_,
205 PP_NATIVE_NACL_PROCESS_TYPE);
208 void Plugin::BitcodeDidTranslate(int32_t pp_error) {
209 PLUGIN_PRINTF(("Plugin::BitcodeDidTranslate (pp_error=%" NACL_PRId32 ")\n",
210 pp_error));
211 if (pp_error != PP_OK) {
212 // Error should have been reported by pnacl. Just return.
213 return;
216 // Inform JavaScript that we successfully translated the bitcode to a nexe.
217 PP_FileHandle handle = pnacl_coordinator_->TakeTranslatedFileHandle();
219 PP_NaClFileInfo info;
220 info.handle = handle;
221 info.token_lo = 0;
222 info.token_hi = 0;
223 LoadNaClModule(
224 info,
225 false, /* uses_nonsfi_mode */
226 PP_PNACL_PROCESS_TYPE);
229 void Plugin::NaClManifestFileDidOpen(int32_t pp_error) {
230 PLUGIN_PRINTF(("Plugin::NaClManifestFileDidOpen (pp_error=%"
231 NACL_PRId32 ")\n", pp_error));
232 if (pp_error != PP_OK)
233 return;
235 PP_Var pp_program_url;
236 PP_PNaClOptions pnacl_options = {PP_FALSE, PP_FALSE, PP_FALSE, 2};
237 PP_Bool uses_nonsfi_mode;
238 if (nacl_interface_->GetManifestProgramURL(
239 pp_instance(), &pp_program_url, &pnacl_options, &uses_nonsfi_mode)) {
240 std::string program_url = pp::Var(pp::PASS_REF, pp_program_url).AsString();
241 // TODO(teravest): Make ProcessNaClManifest take responsibility for more of
242 // this function.
243 nacl_interface_->ProcessNaClManifest(pp_instance(), program_url.c_str());
244 uses_nonsfi_mode_ = PP_ToBool(uses_nonsfi_mode);
245 if (pnacl_options.translate) {
246 pp::CompletionCallback translate_callback =
247 callback_factory_.NewCallback(&Plugin::BitcodeDidTranslate);
248 pnacl_coordinator_.reset(
249 PnaclCoordinator::BitcodeToNative(this,
250 program_url,
251 pnacl_options,
252 translate_callback));
253 return;
254 } else {
255 pp::CompletionCallback open_callback =
256 callback_factory_.NewCallback(&Plugin::NexeFileDidOpen);
257 // Will always call the callback on success or failure.
258 nacl_interface_->DownloadNexe(pp_instance(),
259 program_url.c_str(),
260 &nexe_file_info_,
261 open_callback.pp_completion_callback());
262 return;
267 void Plugin::ReportLoadError(const ErrorInfo& error_info) {
268 nacl_interface_->ReportLoadError(pp_instance(),
269 error_info.error_code(),
270 error_info.message().c_str());
273 } // namespace plugin