• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 The Chromium Authors
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 "components/nacl/renderer/plugin/plugin.h"
6 
7 #include <sys/stat.h>
8 #include <sys/types.h>
9 
10 #include <string>
11 
12 #include "base/check.h"
13 #include "components/nacl/renderer/plugin/nacl_subprocess.h"
14 #include "components/nacl/renderer/plugin/plugin_error.h"
15 #include "components/nacl/renderer/plugin/service_runtime.h"
16 #include "components/nacl/renderer/ppb_nacl_private.h"
17 #include "ppapi/c/pp_errors.h"
18 #include "ppapi/cpp/module.h"
19 
20 namespace {
21 
NoOpCallback(void * user_data,int32_t result)22 void NoOpCallback(void* user_data, int32_t result) {
23 }
24 
25 }
26 
27 namespace plugin {
28 
ShutDownSubprocesses()29 void Plugin::ShutDownSubprocesses() {
30   // Shut down service runtime. This must be done before all other calls so
31   // they don't block forever when waiting for the upcall thread to exit.
32   main_subprocess_.Shutdown();
33 }
34 
LoadNaClModule(PP_NaClFileInfo file_info,PP_NaClAppProcessType process_type)35 void Plugin::LoadNaClModule(PP_NaClFileInfo file_info,
36                             PP_NaClAppProcessType process_type) {
37   CHECK(pp::Module::Get()->core()->IsMainThread());
38   // Before forking a new sel_ldr process, ensure that we do not leak
39   // the ServiceRuntime object for an existing subprocess, and that any
40   // associated listener threads do not go unjoined because if they
41   // outlive the Plugin object, they will not be memory safe.
42   ShutDownSubprocesses();
43   pp::Var manifest_base_url =
44       pp::Var(pp::PASS_REF,
45               nacl::PPBNaClPrivate::GetManifestBaseURL(pp_instance()));
46   std::string manifest_base_url_str = manifest_base_url.AsString();
47 
48   SelLdrStartParams params(manifest_base_url_str,
49                            file_info,
50                            process_type);
51   ErrorInfo error_info;
52   ServiceRuntime* service_runtime =
53       new ServiceRuntime(this, pp_instance(), /*main_service_runtime=*/true);
54   main_subprocess_.set_service_runtime(service_runtime);
55 
56   service_runtime->StartSelLdr(params,
57                                pp::CompletionCallback(NoOpCallback, NULL));
58 }
59 
LoadHelperNaClModule(const std::string & helper_url,PP_NaClFileInfo file_info,NaClSubprocess * subprocess_to_init,pp::CompletionCallback callback)60 void Plugin::LoadHelperNaClModule(const std::string& helper_url,
61                                   PP_NaClFileInfo file_info,
62                                   NaClSubprocess* subprocess_to_init,
63                                   pp::CompletionCallback callback) {
64   CHECK(pp::Module::Get()->core()->IsMainThread());
65   // Do not report UMA stats for translator-related nexes.
66   // TODO(sehr): define new UMA stats for translator related nexe events.
67   SelLdrStartParams params(helper_url,
68                            file_info,
69                            PP_PNACL_TRANSLATOR_PROCESS_TYPE);
70   ServiceRuntime* service_runtime =
71       new ServiceRuntime(this, pp_instance(),
72                          /*main_service_runtime=*/false);
73 
74   subprocess_to_init->set_service_runtime(service_runtime);
75   service_runtime->StartSelLdr(params, callback);
76 }
77 
78 // All failures of this function will show up as "Missing Plugin-in", so
79 // there is no need to log to JS console that there was an initialization
80 // failure. Note that module loading functions will log their own errors.
Init(uint32_t argc,const char * argn[],const char * argv[])81 bool Plugin::Init(uint32_t argc, const char* argn[], const char* argv[]) {
82   nacl::PPBNaClPrivate::InitializePlugin(pp_instance(), argc, argn, argv);
83   pp::CompletionCallback open_cb =
84       callback_factory_.NewCallback(&Plugin::NaClManifestFileDidOpen);
85   nacl::PPBNaClPrivate::RequestNaClManifest(pp_instance(),
86                                             open_cb.pp_completion_callback());
87   return true;
88 }
89 
Plugin(PP_Instance pp_instance)90 Plugin::Plugin(PP_Instance pp_instance)
91     : pp::Instance(pp_instance), uma_interface_(this) {
92   callback_factory_.Initialize(this);
93 
94   // Notify PPBNaClPrivate that the instance is created before altering any
95   // state that it tracks.
96   nacl::PPBNaClPrivate::InstanceCreated(pp_instance);
97   nexe_file_info_ = kInvalidNaClFileInfo;
98 }
99 
~Plugin()100 Plugin::~Plugin() {
101   // Destroy the coordinator while the rest of the data is still there
102   pnacl_coordinator_.reset(NULL);
103 
104   nacl::PPBNaClPrivate::InstanceDestroyed(pp_instance());
105 
106   // ShutDownSubprocesses shuts down the main subprocess, which shuts
107   // down the main ServiceRuntime object, which kills the subprocess.
108   // As a side effect of the subprocess being killed, the reverse
109   // services thread(s) will get EOF on the reverse channel(s), and
110   // the thread(s) will exit.  In ServiceRuntime::Shutdown, we invoke
111   // ReverseService::WaitForServiceThreadsToExit(), so that there will
112   // not be an extent thread(s) hanging around.  This means that the
113   // ~Plugin will block until this happens.  This is a requirement,
114   // since the renderer should be free to unload the plugin code, and
115   // we cannot have threads running code that gets unloaded before
116   // they exit.
117   //
118   // By waiting for the threads here, we also ensure that the Plugin
119   // object and the subprocess and ServiceRuntime objects is not
120   // (fully) destroyed while the threads are running, so resources
121   // that are destroyed after ShutDownSubprocesses (below) are
122   // guaranteed to be live and valid for access from the service
123   // threads.
124   //
125   // The main_subprocess object, which wraps the main service_runtime
126   // object, is dtor'd implicitly after the explicit code below runs,
127   // so the main service runtime object will not have been dtor'd,
128   // though the Shutdown method may have been called, during the
129   // lifetime of the service threads.
130   ShutDownSubprocesses();
131 }
132 
HandleDocumentLoad(const pp::URLLoader & url_loader)133 bool Plugin::HandleDocumentLoad(const pp::URLLoader& url_loader) {
134   // We don't know if the plugin will handle the document load, but return
135   // true in order to give it a chance to respond once the proxy is started.
136   return true;
137 }
138 
NexeFileDidOpen(int32_t pp_error)139 void Plugin::NexeFileDidOpen(int32_t pp_error) {
140   if (pp_error != PP_OK)
141     return;
142   LoadNaClModule(nexe_file_info_, PP_NATIVE_NACL_PROCESS_TYPE);
143 }
144 
BitcodeDidTranslate(int32_t pp_error)145 void Plugin::BitcodeDidTranslate(int32_t pp_error) {
146   if (pp_error != PP_OK) {
147     // Error should have been reported by pnacl. Just return.
148     return;
149   }
150 
151   // Inform JavaScript that we successfully translated the bitcode to a nexe.
152   PP_FileHandle handle = pnacl_coordinator_->TakeTranslatedFileHandle();
153 
154   PP_NaClFileInfo info;
155   info.handle = handle;
156   info.token_lo = 0;
157   info.token_hi = 0;
158   LoadNaClModule(info, PP_PNACL_PROCESS_TYPE);
159 }
160 
NaClManifestFileDidOpen(int32_t pp_error)161 void Plugin::NaClManifestFileDidOpen(int32_t pp_error) {
162   if (pp_error != PP_OK)
163     return;
164 
165   PP_Var pp_program_url;
166   PP_PNaClOptions pnacl_options = {PP_FALSE, PP_FALSE, PP_FALSE, 2};
167   if (nacl::PPBNaClPrivate::GetManifestProgramURL(
168           pp_instance(), &pp_program_url, &pnacl_options)) {
169     std::string program_url = pp::Var(pp::PASS_REF, pp_program_url).AsString();
170     // TODO(teravest): Make ProcessNaClManifest take responsibility for more of
171     // this function.
172     nacl::PPBNaClPrivate::ProcessNaClManifest(pp_instance(),
173                                               program_url.c_str());
174     if (pnacl_options.translate) {
175       pp::CompletionCallback translate_callback =
176           callback_factory_.NewCallback(&Plugin::BitcodeDidTranslate);
177       pnacl_coordinator_.reset(
178           PnaclCoordinator::BitcodeToNative(this,
179                                             program_url,
180                                             pnacl_options,
181                                             translate_callback));
182       return;
183     } else {
184       pp::CompletionCallback open_callback =
185           callback_factory_.NewCallback(&Plugin::NexeFileDidOpen);
186       // Will always call the callback on success or failure.
187       nacl::PPBNaClPrivate::DownloadNexe(
188           pp_instance(),
189           program_url.c_str(),
190           &nexe_file_info_,
191           open_callback.pp_completion_callback());
192       return;
193     }
194   }
195 }
196 
ReportLoadError(const ErrorInfo & error_info)197 void Plugin::ReportLoadError(const ErrorInfo& error_info) {
198   nacl::PPBNaClPrivate::ReportLoadError(pp_instance(),
199                                         error_info.error_code(),
200                                         error_info.message().c_str());
201 }
202 
203 }  // namespace plugin
204