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