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;
47 namespace ppapi_proxy {
56 class Plugin : public pp::Instance {
58 // Factory method for creation.
59 static Plugin* New(PP_Instance instance);
61 // ----- Methods inherited from pp::Instance:
63 // Initializes this plugin with <embed/object ...> tag attribute count |argc|,
64 // names |argn| and values |argn|. Returns false on failure.
65 // Gets called by the browser right after New().
66 virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]);
68 // Handles document load, when the plugin is a MIME type handler.
69 virtual bool HandleDocumentLoad(const pp::URLLoader& url_loader);
71 // ----- Plugin interface support.
74 // NaCl module can be loaded given a DescWrapper.
76 // Starts NaCl module but does not wait until low-level
77 // initialization (e.g., ld.so dynamic loading of manifest files) is
78 // done. The module will become ready later, asynchronously. Other
79 // event handlers should block until the module is ready before
80 // trying to communicate with it, i.e., until nacl_ready_state is
83 // NB: currently we do not time out, so if the untrusted code
84 // does not signal that it is ready, then we will deadlock the main
85 // thread of the renderer on this subsequent event delivery. We
86 // should include a time-out at which point we declare the
87 // nacl_ready_state to be done, and let the normal crash detection
88 // mechanism(s) take over.
90 // Updates nacl_module_origin() and nacl_module_url().
91 void LoadNaClModule(nacl::DescWrapper* wrapper,
92 bool enable_dyncode_syscalls,
93 bool enable_exception_handling,
94 bool enable_crash_throttling,
95 const pp::CompletionCallback& init_done_cb,
96 const pp::CompletionCallback& crash_cb);
98 // Finish hooking interfaces up, after low-level initialization is
100 bool LoadNaClModuleContinuationIntern(ErrorInfo* error_info);
102 // Continuation for starting SRPC/JSProxy services as appropriate.
103 // This is invoked as a callback when the NaCl module makes the
104 // init_done reverse RPC to tell us that low-level initialization
105 // such as ld.so processing is done. That initialization requires
106 // that the main thread be free in order to do Pepper
107 // main-thread-only operations such as file processing.
108 bool LoadNaClModuleContinuation(int32_t pp_error);
111 // A helper SRPC NaCl module can be loaded given a DescWrapper.
112 // Blocks until the helper module signals initialization is done.
113 // Does not update nacl_module_origin().
114 // Returns NULL or the NaClSubprocess of the new helper NaCl module.
115 NaClSubprocess* LoadHelperNaClModule(nacl::DescWrapper* wrapper,
116 const Manifest* manifest,
117 ErrorInfo* error_info);
119 // Returns the argument value for the specified key, or NULL if not found.
120 std::string LookupArgument(const std::string& key) const;
122 enum LengthComputable {
123 LENGTH_IS_NOT_COMPUTABLE = 0,
124 LENGTH_IS_COMPUTABLE = 1
126 // Report successful loading of a module.
127 void ReportLoadSuccess(LengthComputable length_computable,
128 uint64_t loaded_bytes,
129 uint64_t total_bytes);
130 // Report an error that was encountered while loading a module.
131 void ReportLoadError(const ErrorInfo& error_info);
132 // Report loading a module was aborted, typically due to user action.
133 void ReportLoadAbort();
135 // Write a text string on the JavaScript console.
136 void AddToConsole(const nacl::string& text);
138 // Dispatch a JavaScript event to indicate a key step in loading.
139 // |event_type| is a character string indicating which type of progress
140 // event (loadstart, progress, error, abort, load, loadend). Events are
141 // enqueued on the JavaScript event loop, which then calls back through
142 // DispatchProgressEvent.
143 void EnqueueProgressEvent(PP_NaClEventType event_type);
144 void EnqueueProgressEvent(PP_NaClEventType event_type,
145 const nacl::string& url,
146 LengthComputable length_computable,
147 uint64_t loaded_bytes,
148 uint64_t total_bytes);
150 // Report the error code that sel_ldr produces when starting a nexe.
151 void ReportSelLdrLoadStatus(int status);
153 // Report nexe death after load to JS and shut down the proxy.
154 void ReportDeadNexe();
156 // URL resolution support.
157 // plugin_base_url is the URL used for resolving relative URLs used in
159 nacl::string plugin_base_url() const { return plugin_base_url_; }
160 void set_plugin_base_url(const nacl::string& url) { plugin_base_url_ = url; }
161 // manifest_base_url is the URL used for resolving relative URLs mentioned
162 // in manifest files. If the manifest is a data URI, this is an empty string.
163 nacl::string manifest_base_url() const { return manifest_base_url_; }
164 void set_manifest_base_url(const nacl::string& url) {
165 manifest_base_url_ = url;
168 // The state of readiness of the plugin.
170 // The trusted plugin begins in this ready state.
172 // The manifest file has been requested, but not yet received.
174 // This state is unused.
175 HEADERS_RECEIVED = 2,
176 // The manifest file has been received and the nexe successfully requested.
178 // The nexe has been loaded and the proxy started, so it is ready for
179 // interaction with the page.
182 bool nexe_error_reported() const { return nexe_error_reported_; }
183 void set_nexe_error_reported(bool val) {
184 nexe_error_reported_ = val;
187 nacl::DescWrapperFactory* wrapper_factory() const { return wrapper_factory_; }
189 // Requests a NaCl manifest download from a |url| relative to the page origin.
190 void RequestNaClManifest(const nacl::string& url);
192 // The size returned when a file download operation is unable to determine
193 // the size of the file to load. W3C ProgressEvents specify that unknown
195 static const uint64_t kUnknownBytes = 0;
197 // Called back by CallOnMainThread. Dispatches the first enqueued progress
199 void DispatchProgressEvent(int32_t result);
201 // Requests a URL asynchronously resulting in a call to pp_callback with
202 // a PP_Error indicating status. On success an open file descriptor
203 // corresponding to the url body is recorded for further lookup.
204 bool StreamAsFile(const nacl::string& url,
205 PP_CompletionCallback pp_callback);
207 // Returns rich information for a file retrieved by StreamAsFile(). This info
208 // contains a file descriptor. The caller must take ownership of this
210 struct NaClFileInfo GetFileInfo(const nacl::string& url);
212 // A helper function that gets the scheme type for |url|. Uses URLUtil_Dev
213 // interface which this class has as a member.
214 UrlSchemeType GetUrlScheme(const std::string& url);
216 // A helper function that indicates if |url| can be requested by the document
217 // under the same-origin policy. Strictly speaking, it may be possible for the
218 // document to request the URL using CORS even if this function returns false.
219 bool DocumentCanRequest(const std::string& url);
221 void set_last_error_string(const nacl::string& error);
223 // The MIME type used to instantiate this instance of the NaCl plugin.
224 // Typically, the MIME type will be application/x-nacl. However, if the NEXE
225 // is being used as a content type handler for another content type (such as
226 // PDF), then this function will return that type.
227 const nacl::string& mime_type() const { return mime_type_; }
228 // The default MIME type for the NaCl plugin.
229 static const char* const kNaClMIMEType;
230 // The MIME type for the plugin when using PNaCl.
231 static const char* const kPnaclMIMEType;
232 // Returns true if PPAPI Dev interfaces should be allowed.
233 bool enable_dev_interfaces() { return enable_dev_interfaces_; }
235 Manifest const* manifest() const { return manifest_.get(); }
236 const pp::URLUtil_Dev* url_util() const { return url_util_; }
238 int exit_status() const { return exit_status_; }
239 // set_exit_status may be called off the main thread.
240 void set_exit_status(int exit_status);
242 const PPB_NaCl_Private* nacl_interface() const { return nacl_interface_; }
243 pp::UMAPrivate& uma_interface() { return uma_interface_; }
246 NACL_DISALLOW_COPY_AND_ASSIGN(Plugin);
247 // Prevent construction and destruction from outside the class:
248 // must use factory New() method instead.
249 explicit Plugin(PP_Instance instance);
250 // The browser will invoke the destructor via the pp::Instance
251 // pointer to this object, not from base's Delete().
254 bool EarlyInit(int argc, const char* argn[], const char* argv[]);
255 // Shuts down socket connection, service runtime, and receive thread,
256 // in this order, for the main nacl subprocess.
257 void ShutDownSubprocesses();
259 // Access the service runtime for the main NaCl subprocess.
260 ServiceRuntime* main_service_runtime() const {
261 return main_subprocess_.service_runtime();
264 // Histogram helper functions, internal to Plugin so they can use
265 // uma_interface_ normally.
266 void HistogramTimeSmall(const std::string& name, int64_t ms);
267 void HistogramTimeMedium(const std::string& name, int64_t ms);
268 void HistogramTimeLarge(const std::string& name, int64_t ms);
269 void HistogramSizeKB(const std::string& name, int32_t sample);
270 void HistogramEnumerate(const std::string& name,
273 int out_of_range_replacement);
274 void HistogramEnumerateOsArch(const std::string& sandbox_isa);
275 void HistogramEnumerateLoadStatus(PluginErrorCode error_code,
277 void HistogramEnumerateSelLdrLoadStatus(NaClErrorCode error_code,
279 void HistogramEnumerateManifestIsDataURI(bool is_data_uri);
280 void HistogramHTTPStatusCode(const std::string& name, int status);
282 // Load a nacl module from the file specified in wrapper.
283 // Only to be used from a background (non-main) thread.
284 // This will fully initialize the |subprocess| if the load was successful.
285 bool LoadNaClModuleFromBackgroundThread(nacl::DescWrapper* wrapper,
286 NaClSubprocess* subprocess,
287 const Manifest* manifest,
288 const SelLdrStartParams& params);
290 // Start sel_ldr from the main thread, given the start params.
291 // |pp_error| is set by CallOnMainThread (should be PP_OK).
292 void StartSelLdrOnMainThread(int32_t pp_error,
293 ServiceRuntime* service_runtime,
294 const SelLdrStartParams& params,
295 pp::CompletionCallback callback);
297 // Signals that StartSelLdr has finished.
298 void SignalStartSelLdrDone(int32_t pp_error,
300 ServiceRuntime* service_runtime);
302 void LoadNexeAndStart(int32_t pp_error,
303 nacl::DescWrapper* wrapper,
304 ServiceRuntime* service_runtime,
305 const pp::CompletionCallback& crash_cb);
307 // Callback used when getting the URL for the .nexe file. If the URL loading
308 // is successful, the file descriptor is opened and can be passed to sel_ldr
309 // with the sandbox on.
310 void NexeFileDidOpen(int32_t pp_error);
311 void NexeFileDidOpenContinuation(int32_t pp_error);
313 // Callback used when the reverse channel closes. This is an
314 // asynchronous event that might turn into a JavaScript error or
315 // crash event -- this is controlled by the two state variables
316 // nacl_ready_state_ and nexe_error_reported_: If an error or crash
317 // had already been reported, no additional crash event is
318 // generated. If no error has been reported but nacl_ready_state_
319 // is not DONE, then the loadend event has not been reported, and we
320 // enqueue an error event followed by loadend. If nacl_ready_state_
321 // is DONE, then we are in the post-loadend (we need temporal
322 // predicate symbols), and we enqueue a crash event.
323 void NexeDidCrash(int32_t pp_error);
325 // Callback used when a .nexe is translated from bitcode. If the translation
326 // is successful, the file descriptor is opened and can be passed to sel_ldr
327 // with the sandbox on.
328 void BitcodeDidTranslate(int32_t pp_error);
329 void BitcodeDidTranslateContinuation(int32_t pp_error);
331 // NaCl ISA selection manifest file support. The manifest file is specified
332 // using the "nacl" attribute in the <embed> tag. First, the manifest URL (or
333 // data: URI) is fetched, then the JSON is parsed. Once a valid .nexe is
334 // chosen for the sandbox ISA, any current service runtime is shut down, the
335 // .nexe is loaded and run.
337 // Callback used when getting the manifest file as a buffer (e.g., data URIs)
338 void NaClManifestBufferReady(int32_t pp_error);
340 // Callback used when getting the manifest file as a local file descriptor.
341 void NaClManifestFileDidOpen(int32_t pp_error);
343 // Processes the JSON manifest string and starts loading the nexe.
344 void ProcessNaClManifest(const nacl::string& manifest_json);
346 // Parses the JSON in |manifest_json| and retains a Manifest in
347 // |manifest_| for use by subsequent resource lookups.
348 // On success, |true| is returned and |manifest_| is updated to
349 // contain a Manifest that is used by SelectNexeURLFromManifest.
350 // On failure, |false| is returned, and |manifest_| is unchanged.
351 bool SetManifestObject(const nacl::string& manifest_json,
352 ErrorInfo* error_info);
354 // Logs timing information to a UMA histogram, and also logs the same timing
355 // information divided by the size of the nexe to another histogram.
356 void HistogramStartupTimeSmall(const std::string& name, float dt);
357 void HistogramStartupTimeMedium(const std::string& name, float dt);
359 // This NEXE is being used as a content type handler rather than directly by
361 bool NexeIsContentHandler() const;
363 // Callback used when loading a URL for SRPC-based StreamAsFile().
364 void UrlDidOpenForStreamAsFile(int32_t pp_error,
365 FileDownloader*& url_downloader,
366 PP_CompletionCallback pp_callback);
368 // Copy the main service runtime's most recent NaClLog output to the
369 // JavaScript console. Valid to use only after a crash, e.g., via a
370 // detail level LOG_FATAL NaClLog entry. If the crash was not due
371 // to a LOG_FATAL this method will do nothing.
372 void CopyCrashLogToJsConsole();
374 // Open an app file by requesting a file descriptor from the browser. This
375 // method first checks that the url is for an installed file before making the
376 // request so it won't slow down non-installed file downloads.
377 bool OpenURLFast(const nacl::string& url, FileDownloader* downloader);
379 void set_nacl_ready_state(ReadyState state);
381 void SetExitStatusOnMainThread(int32_t pp_error, int exit_status);
383 std::map<std::string, std::string> args_;
385 // Keep track of the NaCl module subprocess that was spun up in the plugin.
386 NaClSubprocess main_subprocess_;
388 nacl::string plugin_base_url_;
389 nacl::string manifest_base_url_;
390 nacl::string manifest_url_;
391 ReadyState nacl_ready_state_;
392 bool nexe_error_reported_; // error or crash reported
394 nacl::DescWrapperFactory* wrapper_factory_;
396 // File download support. |nexe_downloader_| can be opened with a specific
397 // callback to run when the file has been downloaded and is opened for
398 // reading. We use one downloader for all URL downloads to prevent issuing
399 // multiple GETs that might arrive out of order. For example, this will
400 // prevent a GET of a NaCl manifest while a .nexe GET is pending. Note that
401 // this will also prevent simultaneous handling of multiple .nexes on a page.
402 FileDownloader nexe_downloader_;
403 pp::CompletionCallbackFactory<Plugin> callback_factory_;
405 nacl::scoped_ptr<PnaclCoordinator> pnacl_coordinator_;
407 // The manifest dictionary. Used for looking up resources to be loaded.
408 nacl::scoped_ptr<Manifest> manifest_;
409 // URL processing interface for use in looking up resources in manifests.
410 const pp::URLUtil_Dev* url_util_;
412 // PPAPI Dev interfaces are disabled by default.
413 bool enable_dev_interfaces_;
415 // A flag indicating if the NaCl executable is being loaded from an installed
416 // application. This flag is used to bucket UMA statistics more precisely to
417 // help determine whether nexe loading problems are caused by networking
418 // issues. (Installed applications will be loaded from disk.)
419 // Unfortunately, the definition of what it means to be part of an installed
420 // application is a little murky - for example an installed application can
421 // register a mime handler that loads NaCl executables into an arbitrary web
422 // page. As such, the flag actually means "our best guess, based on the URLs
423 // for NaCl resources that we have seen so far".
426 // If we get a DidChangeView event before the nexe is loaded, we store it and
427 // replay it to nexe after it's loaded. We need to replay when this View
428 // resource is non-is_null().
429 pp::View view_to_replay_;
431 // If we get a HandleDocumentLoad event before the nexe is loaded, we store
432 // it and replay it to nexe after it's loaded. We need to replay when this
433 // URLLoader resource is non-is_null().
434 pp::URLLoader document_load_to_replay_;
436 nacl::string mime_type_;
438 // Keep track of the FileDownloaders created to fetch urls.
439 std::set<FileDownloader*> url_downloaders_;
440 // Keep track of file descriptors opened by StreamAsFile().
441 // These are owned by the browser.
442 std::map<nacl::string, NaClFileInfoAutoCloser*> url_file_info_map_;
444 // Used for NexeFileDidOpenContinuation
451 // Callback to receive .nexe and .dso download progress notifications.
452 static void UpdateDownloadProgress(
453 PP_Instance pp_instance,
454 PP_Resource pp_resource,
456 int64_t total_bytes_to_be_sent,
457 int64_t bytes_received,
458 int64_t total_bytes_to_be_received);
460 // Finds the file downloader which owns the given URL loader. This is used
461 // in UpdateDownloadProgress to map a url loader back to the URL being
463 const FileDownloader* FindFileDownloader(PP_Resource url_loader) const;
465 int64_t time_of_last_progress_event_;
468 const PPB_NaCl_Private* nacl_interface_;
469 pp::UMAPrivate uma_interface_;
472 } // namespace plugin
474 #endif // NATIVE_CLIENT_SRC_TRUSTED_PLUGIN_PLUGIN_H_