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
4 // found in the LICENSE file.
6 // The portable representation of an instance and root scriptable object.
7 // The PPAPI version of the plugin instantiates a subclass of this class.
9 #ifndef NATIVE_CLIENT_SRC_TRUSTED_PLUGIN_PLUGIN_H_
10 #define NATIVE_CLIENT_SRC_TRUSTED_PLUGIN_PLUGIN_H_
19 #include "native_client/src/include/nacl_macros.h"
20 #include "native_client/src/include/nacl_scoped_ptr.h"
21 #include "native_client/src/include/nacl_string.h"
22 #include "native_client/src/trusted/validator/nacl_file_info.h"
24 #include "ppapi/c/private/ppb_nacl_private.h"
25 #include "ppapi/cpp/instance.h"
26 #include "ppapi/cpp/private/uma_private.h"
27 #include "ppapi/cpp/url_loader.h"
28 #include "ppapi/cpp/var.h"
29 #include "ppapi/cpp/view.h"
31 #include "ppapi/native_client/src/trusted/plugin/file_downloader.h"
32 #include "ppapi/native_client/src/trusted/plugin/nacl_subprocess.h"
33 #include "ppapi/native_client/src/trusted/plugin/pnacl_coordinator.h"
34 #include "ppapi/native_client/src/trusted/plugin/service_runtime.h"
35 #include "ppapi/native_client/src/trusted/plugin/utility.h"
39 class DescWrapperFactory;
43 class CompletionCallback;
53 class Plugin : public pp::Instance {
55 explicit Plugin(PP_Instance instance);
57 // ----- Methods inherited from pp::Instance:
59 // Initializes this plugin with <embed/object ...> tag attribute count |argc|,
60 // names |argn| and values |argn|. Returns false on failure.
61 // Gets called by the browser right after New().
62 virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]);
64 // Handles document load, when the plugin is a MIME type handler.
65 virtual bool HandleDocumentLoad(const pp::URLLoader& url_loader);
67 // ----- Plugin interface support.
70 // NaCl module can be loaded given a DescWrapper.
72 // Starts NaCl module but does not wait until low-level
73 // initialization (e.g., ld.so dynamic loading of manifest files) is
74 // done. The module will become ready later, asynchronously. Other
75 // event handlers should block until the module is ready before
76 // trying to communicate with it, i.e., until nacl_ready_state is
79 // NB: currently we do not time out, so if the untrusted code
80 // does not signal that it is ready, then we will deadlock the main
81 // thread of the renderer on this subsequent event delivery. We
82 // should include a time-out at which point we declare the
83 // nacl_ready_state to be done, and let the normal crash detection
84 // mechanism(s) take over.
86 // Updates nacl_module_origin() and nacl_module_url().
87 void LoadNaClModule(nacl::DescWrapper* wrapper,
88 bool uses_nonsfi_mode,
89 bool enable_dyncode_syscalls,
90 bool enable_exception_handling,
91 bool enable_crash_throttling,
92 const pp::CompletionCallback& init_done_cb,
93 const pp::CompletionCallback& crash_cb);
95 // Finish hooking interfaces up, after low-level initialization is
97 bool LoadNaClModuleContinuationIntern();
99 // Continuation for starting SRPC/JSProxy services as appropriate.
100 // This is invoked as a callback when the NaCl module makes the
101 // init_done reverse RPC to tell us that low-level initialization
102 // such as ld.so processing is done. That initialization requires
103 // that the main thread be free in order to do Pepper
104 // main-thread-only operations such as file processing.
105 bool LoadNaClModuleContinuation(int32_t pp_error);
108 // A helper SRPC NaCl module can be loaded given a DescWrapper.
109 // Blocks until the helper module signals initialization is done.
110 // Does not update nacl_module_origin().
111 // Returns NULL or the NaClSubprocess of the new helper NaCl module.
112 NaClSubprocess* LoadHelperNaClModule(const nacl::string& helper_url,
113 nacl::DescWrapper* wrapper,
115 ErrorInfo* error_info);
117 enum LengthComputable {
118 LENGTH_IS_NOT_COMPUTABLE = 0,
119 LENGTH_IS_COMPUTABLE = 1
121 // Report successful loading of a module.
122 void ReportLoadSuccess(uint64_t loaded_bytes, uint64_t total_bytes);
123 // Report an error that was encountered while loading a module.
124 void ReportLoadError(const ErrorInfo& error_info);
125 // Report loading a module was aborted, typically due to user action.
126 void ReportLoadAbort();
128 // Dispatch a JavaScript event to indicate a key step in loading.
129 // |event_type| is a character string indicating which type of progress
130 // event (loadstart, progress, error, abort, load, loadend). Events are
131 // enqueued on the JavaScript event loop, which then calls back through
132 // DispatchProgressEvent.
133 void EnqueueProgressEvent(PP_NaClEventType event_type,
134 const nacl::string& url,
135 LengthComputable length_computable,
136 uint64_t loaded_bytes,
137 uint64_t total_bytes);
139 // Report the error code that sel_ldr produces when starting a nexe.
140 void ReportSelLdrLoadStatus(int status);
142 nacl::DescWrapperFactory* wrapper_factory() const { return wrapper_factory_; }
144 // Requests a NaCl manifest download from a |url| relative to the page origin.
145 void RequestNaClManifest(const nacl::string& url);
147 // Called back by CallOnMainThread. Dispatches the first enqueued progress
149 void DispatchProgressEvent(int32_t result);
151 // Requests a URL asynchronously resulting in a call to pp_callback with
152 // a PP_Error indicating status. On success an open file descriptor
153 // corresponding to the url body is recorded for further lookup.
154 bool StreamAsFile(const nacl::string& url,
155 const pp::CompletionCallback& callback);
157 // Returns rich information for a file retrieved by StreamAsFile(). This info
158 // contains a file descriptor. The caller must take ownership of this
160 struct NaClFileInfo GetFileInfo(const nacl::string& url);
162 // A helper function that indicates if |url| can be requested by the document
163 // under the same-origin policy. Strictly speaking, it may be possible for the
164 // document to request the URL using CORS even if this function returns false.
165 bool DocumentCanRequest(const std::string& url);
167 // set_exit_status may be called off the main thread.
168 void set_exit_status(int exit_status);
170 const PPB_NaCl_Private* nacl_interface() const { return nacl_interface_; }
171 pp::UMAPrivate& uma_interface() { return uma_interface_; }
174 NACL_DISALLOW_COPY_AND_ASSIGN(Plugin);
175 // The browser will invoke the destructor via the pp::Instance
176 // pointer to this object, not from base's Delete().
179 // Shuts down socket connection, service runtime, and receive thread,
180 // in this order, for the main nacl subprocess.
181 void ShutDownSubprocesses();
183 // Access the service runtime for the main NaCl subprocess.
184 ServiceRuntime* main_service_runtime() const {
185 return main_subprocess_.service_runtime();
188 // Histogram helper functions, internal to Plugin so they can use
189 // uma_interface_ normally.
190 void HistogramTimeSmall(const std::string& name, int64_t ms);
191 void HistogramTimeMedium(const std::string& name, int64_t ms);
192 void HistogramTimeLarge(const std::string& name, int64_t ms);
193 void HistogramSizeKB(const std::string& name, int32_t sample);
194 void HistogramEnumerate(const std::string& name,
197 int out_of_range_replacement);
198 void HistogramEnumerateLoadStatus(PP_NaClError error_code);
199 void HistogramEnumerateSelLdrLoadStatus(NaClErrorCode error_code);
200 void HistogramHTTPStatusCode(const std::string& name, int status);
202 // Load a nacl module from the file specified in wrapper.
203 // Only to be used from a background (non-main) thread.
204 // This will fully initialize the |subprocess| if the load was successful.
205 bool LoadNaClModuleFromBackgroundThread(nacl::DescWrapper* wrapper,
206 NaClSubprocess* subprocess,
208 const SelLdrStartParams& params);
210 // Start sel_ldr from the main thread, given the start params.
211 // |pp_error| is set by CallOnMainThread (should be PP_OK).
212 void StartSelLdrOnMainThread(int32_t pp_error,
213 ServiceRuntime* service_runtime,
214 const SelLdrStartParams& params,
215 pp::CompletionCallback callback);
217 // Signals that StartSelLdr has finished.
218 void SignalStartSelLdrDone(int32_t pp_error,
220 ServiceRuntime* service_runtime);
222 void LoadNexeAndStart(int32_t pp_error,
223 nacl::DescWrapper* wrapper,
224 ServiceRuntime* service_runtime,
225 const pp::CompletionCallback& crash_cb);
227 // Callback used when getting the URL for the .nexe file. If the URL loading
228 // is successful, the file descriptor is opened and can be passed to sel_ldr
229 // with the sandbox on.
230 void NexeFileDidOpen(int32_t pp_error);
231 void NexeFileDidOpenContinuation(int32_t pp_error);
233 // Callback used when the reverse channel closes. This is an
234 // asynchronous event that might turn into a JavaScript error or
235 // crash event -- this is controlled by the two state variables
236 // nacl_ready_state_ and nexe_error_reported_: If an error or crash
237 // had already been reported, no additional crash event is
238 // generated. If no error has been reported but nacl_ready_state_
239 // is not DONE, then the loadend event has not been reported, and we
240 // enqueue an error event followed by loadend. If nacl_ready_state_
241 // is DONE, then we are in the post-loadend (we need temporal
242 // predicate symbols), and we enqueue a crash event.
243 void NexeDidCrash(int32_t pp_error);
245 // Callback used when a .nexe is translated from bitcode. If the translation
246 // is successful, the file descriptor is opened and can be passed to sel_ldr
247 // with the sandbox on.
248 void BitcodeDidTranslate(int32_t pp_error);
249 void BitcodeDidTranslateContinuation(int32_t pp_error);
251 // NaCl ISA selection manifest file support. The manifest file is specified
252 // using the "nacl" attribute in the <embed> tag. First, the manifest URL (or
253 // data: URI) is fetched, then the JSON is parsed. Once a valid .nexe is
254 // chosen for the sandbox ISA, any current service runtime is shut down, the
255 // .nexe is loaded and run.
257 // Callback used when getting the manifest file as a local file descriptor.
258 void NaClManifestFileDidOpen(int32_t pp_error);
260 // Processes the JSON manifest string and starts loading the nexe.
261 void ProcessNaClManifest(const nacl::string& manifest_json);
263 // Parses the JSON in |manifest_json| and retains a Manifest in
264 // |manifest_| for use by subsequent resource lookups.
265 // On success, |true| is returned and |manifest_| is updated to
266 // contain a Manifest that is used by SelectNexeURLFromManifest.
267 // On failure, |false| is returned, and |manifest_| is unchanged.
268 bool SetManifestObject(const nacl::string& manifest_json);
270 // Logs timing information to a UMA histogram, and also logs the same timing
271 // information divided by the size of the nexe to another histogram.
272 void HistogramStartupTimeSmall(const std::string& name, float dt);
273 void HistogramStartupTimeMedium(const std::string& name, float dt);
275 // Callback used when loading a URL for SRPC-based StreamAsFile().
276 void UrlDidOpenForStreamAsFile(int32_t pp_error,
277 FileDownloader* url_downloader,
278 pp::CompletionCallback pp_callback);
280 // Open an app file by requesting a file descriptor from the browser. This
281 // method first checks that the url is for an installed file before making the
282 // request so it won't slow down non-installed file downloads.
283 bool OpenURLFast(const nacl::string& url, FileDownloader* downloader);
285 void SetExitStatusOnMainThread(int32_t pp_error, int exit_status);
287 // Keep track of the NaCl module subprocess that was spun up in the plugin.
288 NaClSubprocess main_subprocess_;
290 bool uses_nonsfi_mode_;
292 nacl::DescWrapperFactory* wrapper_factory_;
294 // File download support. |nexe_downloader_| can be opened with a specific
295 // callback to run when the file has been downloaded and is opened for
296 // reading. We use one downloader for all URL downloads to prevent issuing
297 // multiple GETs that might arrive out of order. For example, this will
298 // prevent a GET of a NaCl manifest while a .nexe GET is pending. Note that
299 // this will also prevent simultaneous handling of multiple .nexes on a page.
300 FileDownloader nexe_downloader_;
301 pp::CompletionCallbackFactory<Plugin> callback_factory_;
303 nacl::scoped_ptr<PnaclCoordinator> pnacl_coordinator_;
305 // Keep track of the FileDownloaders created to fetch urls.
306 std::set<FileDownloader*> url_downloaders_;
307 // Keep track of file descriptors opened by StreamAsFile().
308 // These are owned by the browser.
309 std::map<nacl::string, NaClFileInfoAutoCloser*> url_file_info_map_;
311 // Callback to receive .nexe and .dso download progress notifications.
312 static void UpdateDownloadProgress(
313 PP_Instance pp_instance,
314 PP_Resource pp_resource,
316 int64_t total_bytes_to_be_sent,
317 int64_t bytes_received,
318 int64_t total_bytes_to_be_received);
320 // Finds the file downloader which owns the given URL loader. This is used
321 // in UpdateDownloadProgress to map a url loader back to the URL being
323 const FileDownloader* FindFileDownloader(PP_Resource url_loader) const;
325 int64_t time_of_last_progress_event_;
328 // Open times are in microseconds.
329 int64_t nexe_open_time_;
331 PP_Var manifest_data_var_;
332 int32_t manifest_id_;
334 const PPB_NaCl_Private* nacl_interface_;
335 pp::UMAPrivate uma_interface_;
338 } // namespace plugin
340 #endif // NATIVE_CLIENT_SRC_TRUSTED_PLUGIN_PLUGIN_H_