- add sources.
[platform/framework/web/crosswalk.git] / src / ppapi / native_client / src / trusted / plugin / plugin.h
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/private/instance_private.h"
26 #include "ppapi/cpp/url_loader.h"
27 #include "ppapi/cpp/var.h"
28 #include "ppapi/cpp/view.h"
29
30 #include "ppapi/native_client/src/trusted/plugin/file_downloader.h"
31 #include "ppapi/native_client/src/trusted/plugin/nacl_subprocess.h"
32 #include "ppapi/native_client/src/trusted/plugin/pnacl_coordinator.h"
33 #include "ppapi/native_client/src/trusted/plugin/service_runtime.h"
34 #include "ppapi/native_client/src/trusted/plugin/utility.h"
35
36 namespace nacl {
37 class DescWrapper;
38 class DescWrapperFactory;
39 }  // namespace nacl
40
41 namespace pp {
42 class URLLoader;
43 class URLUtil_Dev;
44 }
45
46 namespace ppapi_proxy {
47 class BrowserPpp;
48 }
49
50 namespace plugin {
51
52 class ErrorInfo;
53 class Manifest;
54 class ProgressEvent;
55 class ScriptablePlugin;
56
57 class Plugin : public pp::InstancePrivate {
58  public:
59   // Factory method for creation.
60   static Plugin* New(PP_Instance instance);
61
62   // ----- Methods inherited from pp::Instance:
63
64   // Initializes this plugin with <embed/object ...> tag attribute count |argc|,
65   // names |argn| and values |argn|. Returns false on failure.
66   // Gets called by the browser right after New().
67   virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]);
68
69   // Handles document load, when the plugin is a MIME type handler.
70   virtual bool HandleDocumentLoad(const pp::URLLoader& url_loader);
71
72   // Returns a scriptable reference to this plugin element.
73   // Called by JavaScript document.getElementById(plugin_id).
74   virtual pp::Var GetInstanceObject();
75
76   // ----- Plugin interface support.
77
78   // Load support.
79   // NaCl module can be loaded given a DescWrapper.
80   //
81   // Starts NaCl module but does not wait until low-level
82   // initialization (e.g., ld.so dynamic loading of manifest files) is
83   // done.  The module will become ready later, asynchronously.  Other
84   // event handlers should block until the module is ready before
85   // trying to communicate with it, i.e., until nacl_ready_state is
86   // DONE.
87   //
88   // NB: currently we do not time out, so if the untrusted code
89   // does not signal that it is ready, then we will deadlock the main
90   // thread of the renderer on this subsequent event delivery.  We
91   // should include a time-out at which point we declare the
92   // nacl_ready_state to be done, and let the normal crash detection
93   // mechanism(s) take over.
94   //
95   // Updates nacl_module_origin() and nacl_module_url().
96   bool LoadNaClModule(nacl::DescWrapper* wrapper, ErrorInfo* error_info,
97                       bool enable_dyncode_syscalls,
98                       bool enable_exception_handling,
99                       bool enable_crash_throttling,
100                       const pp::CompletionCallback& init_done_cb,
101                       const pp::CompletionCallback& crash_cb);
102
103   // Finish hooking interfaces up, after low-level initialization is
104   // complete.
105   bool LoadNaClModuleContinuationIntern(ErrorInfo* error_info);
106
107   // Continuation for starting SRPC/JSProxy services as appropriate.
108   // This is invoked as a callback when the NaCl module makes the
109   // init_done reverse RPC to tell us that low-level initialization
110   // such as ld.so processing is done.  That initialization requires
111   // that the main thread be free in order to do Pepper
112   // main-thread-only operations such as file processing.
113   bool LoadNaClModuleContinuation(int32_t pp_error);
114
115   // Load support.
116   // A helper SRPC NaCl module can be loaded given a DescWrapper.
117   // Blocks until the helper module signals initialization is done.
118   // Does not update nacl_module_origin().
119   // Returns NULL or the NaClSubprocess of the new helper NaCl module.
120   NaClSubprocess* LoadHelperNaClModule(nacl::DescWrapper* wrapper,
121                                        const Manifest* manifest,
122                                        ErrorInfo* error_info);
123
124   // Returns the argument value for the specified key, or NULL if not found.
125   // The callee retains ownership of the result.
126   char* LookupArgument(const char* key);
127
128   enum LengthComputable {
129     LENGTH_IS_NOT_COMPUTABLE = 0,
130     LENGTH_IS_COMPUTABLE = 1
131   };
132   // Report successful loading of a module.
133   void ReportLoadSuccess(LengthComputable length_computable,
134                          uint64_t loaded_bytes,
135                          uint64_t total_bytes);
136   // Report an error that was encountered while loading a module.
137   void ReportLoadError(const ErrorInfo& error_info);
138   // Report loading a module was aborted, typically due to user action.
139   void ReportLoadAbort();
140
141   // Write a text string on the JavaScript console.
142   void AddToConsole(const nacl::string& text);
143
144   // Dispatch a JavaScript event to indicate a key step in loading.
145   // |event_type| is a character string indicating which type of progress
146   // event (loadstart, progress, error, abort, load, loadend).  Events are
147   // enqueued on the JavaScript event loop, which then calls back through
148   // DispatchProgressEvent.
149   void EnqueueProgressEvent(const char* event_type);
150   void EnqueueProgressEvent(const char* event_type,
151                             const nacl::string& url,
152                             LengthComputable length_computable,
153                             uint64_t loaded_bytes,
154                             uint64_t total_bytes);
155
156   // Progress event types.
157   static const char* const kProgressEventLoadStart;
158   static const char* const kProgressEventProgress;
159   static const char* const kProgressEventError;
160   static const char* const kProgressEventAbort;
161   static const char* const kProgressEventLoad;
162   static const char* const kProgressEventLoadEnd;
163   static const char* const kProgressEventCrash;
164
165   // Report the error code that sel_ldr produces when starting a nexe.
166   void ReportSelLdrLoadStatus(int status);
167
168   // Report nexe death after load to JS and shut down the proxy.
169   void ReportDeadNexe();
170
171   // URL resolution support.
172   // plugin_base_url is the URL used for resolving relative URLs used in
173   // src="...".
174   nacl::string plugin_base_url() const { return plugin_base_url_; }
175   void set_plugin_base_url(const nacl::string& url) { plugin_base_url_ = url; }
176   // manifest_base_url is the URL used for resolving relative URLs mentioned
177   // in manifest files.  If the manifest is a data URI, this is an empty string.
178   nacl::string manifest_base_url() const { return manifest_base_url_; }
179   void set_manifest_base_url(const nacl::string& url) {
180     manifest_base_url_ = url;
181   }
182
183   // The URL of the manifest file as set by the "src" attribute.
184   // It is not the fully resolved URL if it was set as relative.
185   const nacl::string& manifest_url() const { return manifest_url_; }
186   void set_manifest_url(const nacl::string& manifest_url) {
187     manifest_url_ = manifest_url;
188   }
189
190   // The state of readiness of the plugin.
191   enum ReadyState {
192     // The trusted plugin begins in this ready state.
193     UNSENT = 0,
194     // The manifest file has been requested, but not yet received.
195     OPENED = 1,
196     // This state is unused.
197     HEADERS_RECEIVED = 2,
198     // The manifest file has been received and the nexe successfully requested.
199     LOADING = 3,
200     // The nexe has been loaded and the proxy started, so it is ready for
201     // interaction with the page.
202     DONE = 4
203   };
204   bool nexe_error_reported() const { return nexe_error_reported_; }
205   void set_nexe_error_reported(bool val) {
206     nexe_error_reported_ = val;
207   }
208
209   nacl::DescWrapperFactory* wrapper_factory() const { return wrapper_factory_; }
210
211   // Requests a NaCl manifest download from a |url| relative to the page origin.
212   void RequestNaClManifest(const nacl::string& url);
213
214   // Support for property getting.
215   typedef void (Plugin::* PropertyGetter)(NaClSrpcArg* prop_value);
216   void AddPropertyGet(const nacl::string& prop_name, PropertyGetter getter);
217   bool HasProperty(const nacl::string& prop_name);
218   bool GetProperty(const nacl::string& prop_name, NaClSrpcArg* prop_value);
219   // The supported property getters.
220   void GetExitStatus(NaClSrpcArg* prop_value);
221   void GetLastError(NaClSrpcArg* prop_value);
222   void GetReadyStateProperty(NaClSrpcArg* prop_value);
223
224   // The size returned when a file download operation is unable to determine
225   // the size of the file to load.  W3C ProgressEvents specify that unknown
226   // sizes return 0.
227   static const uint64_t kUnknownBytes = 0;
228
229   // Called back by CallOnMainThread.  Dispatches the first enqueued progress
230   // event.
231   void DispatchProgressEvent(int32_t result);
232
233   // Requests a URL asynchronously resulting in a call to pp_callback with
234   // a PP_Error indicating status. On success an open file descriptor
235   // corresponding to the url body is recorded for further lookup.
236   bool StreamAsFile(const nacl::string& url,
237                     PP_CompletionCallback pp_callback);
238
239   // Returns rich information for a file retrieved by StreamAsFile(). This info
240   // contains a file descriptor. The caller must take ownership of this
241   // descriptor.
242   struct NaClFileInfo GetFileInfo(const nacl::string& url);
243
244   // A helper function that gets the scheme type for |url|. Uses URLUtil_Dev
245   // interface which this class has as a member.
246   UrlSchemeType GetUrlScheme(const std::string& url);
247
248   // A helper function that indicates if |url| can be requested by the document
249   // under the same-origin policy. Strictly speaking, it may be possible for the
250   // document to request the URL using CORS even if this function returns false.
251   bool DocumentCanRequest(const std::string& url);
252
253   // Get the text description of the last error reported by the plugin.
254   const nacl::string& last_error_string() const { return last_error_string_; }
255   void set_last_error_string(const nacl::string& error) {
256     last_error_string_ = error;
257   }
258
259   // The MIME type used to instantiate this instance of the NaCl plugin.
260   // Typically, the MIME type will be application/x-nacl.  However, if the NEXE
261   // is being used as a content type handler for another content type (such as
262   // PDF), then this function will return that type.
263   const nacl::string& mime_type() const { return mime_type_; }
264   // The default MIME type for the NaCl plugin.
265   static const char* const kNaClMIMEType;
266   // The MIME type for the plugin when using PNaCl.
267   static const char* const kPnaclMIMEType;
268   // Returns true if PPAPI Dev interfaces should be allowed.
269   bool enable_dev_interfaces() { return enable_dev_interfaces_; }
270
271   Manifest const* manifest() const { return manifest_.get(); }
272   const pp::URLUtil_Dev* url_util() const { return url_util_; }
273
274   // Extracts the exit status from the (main) service runtime.
275   int exit_status() const {
276     if (NULL == main_service_runtime()) {
277       return -1;
278     }
279     return main_service_runtime()->exit_status();
280   }
281
282   const PPB_NaCl_Private* nacl_interface() const { return nacl_interface_; }
283
284  private:
285   NACL_DISALLOW_COPY_AND_ASSIGN(Plugin);
286   // Prevent construction and destruction from outside the class:
287   // must use factory New() method instead.
288   explicit Plugin(PP_Instance instance);
289   // The browser will invoke the destructor via the pp::Instance
290   // pointer to this object, not from base's Delete().
291   ~Plugin();
292
293   bool EarlyInit(int argc, const char* argn[], const char* argv[]);
294   // Shuts down socket connection, service runtime, and receive thread,
295   // in this order, for the main nacl subprocess.
296   void ShutDownSubprocesses();
297
298   ScriptablePlugin* scriptable_plugin() const { return scriptable_plugin_; }
299   void set_scriptable_plugin(ScriptablePlugin* scriptable_plugin) {
300     scriptable_plugin_ = scriptable_plugin;
301   }
302
303   // Access the service runtime for the main NaCl subprocess.
304   ServiceRuntime* main_service_runtime() const {
305     return main_subprocess_.service_runtime();
306   }
307
308   // Help load a nacl module, from the file specified in wrapper.
309   // This will fully initialize the |subprocess| if the load was successful.
310   bool LoadNaClModuleCommon(nacl::DescWrapper* wrapper,
311                             NaClSubprocess* subprocess,
312                             const Manifest* manifest,
313                             bool should_report_uma,
314                             const SelLdrStartParams& params,
315                             const pp::CompletionCallback& init_done_cb,
316                             const pp::CompletionCallback& crash_cb);
317
318   // Start sel_ldr from the main thread, given the start params.
319   // Sets |success| to true on success.
320   // |pp_error| is set by CallOnMainThread (should be PP_OK).
321   void StartSelLdrOnMainThread(int32_t pp_error,
322                                ServiceRuntime* service_runtime,
323                                const SelLdrStartParams& params,
324                                bool* success);
325
326   // Callback used when getting the URL for the .nexe file.  If the URL loading
327   // is successful, the file descriptor is opened and can be passed to sel_ldr
328   // with the sandbox on.
329   void NexeFileDidOpen(int32_t pp_error);
330   void NexeFileDidOpenContinuation(int32_t pp_error);
331
332   // Callback used when the reverse channel closes.  This is an
333   // asynchronous event that might turn into a JavaScript error or
334   // crash event -- this is controlled by the two state variables
335   // nacl_ready_state_ and nexe_error_reported_: If an error or crash
336   // had already been reported, no additional crash event is
337   // generated.  If no error has been reported but nacl_ready_state_
338   // is not DONE, then the loadend event has not been reported, and we
339   // enqueue an error event followed by loadend.  If nacl_ready_state_
340   // is DONE, then we are in the post-loadend (we need temporal
341   // predicate symbols), and we enqueue a crash event.
342   void NexeDidCrash(int32_t pp_error);
343
344   // Callback used when a .nexe is translated from bitcode.  If the translation
345   // is successful, the file descriptor is opened and can be passed to sel_ldr
346   // with the sandbox on.
347   void BitcodeDidTranslate(int32_t pp_error);
348   void BitcodeDidTranslateContinuation(int32_t pp_error);
349
350   // NaCl ISA selection manifest file support.  The manifest file is specified
351   // using the "nacl" attribute in the <embed> tag.  First, the manifest URL (or
352   // data: URI) is fetched, then the JSON is parsed.  Once a valid .nexe is
353   // chosen for the sandbox ISA, any current service runtime is shut down, the
354   // .nexe is loaded and run.
355
356   // Callback used when getting the manifest file as a buffer (e.g., data URIs)
357   void NaClManifestBufferReady(int32_t pp_error);
358
359   // Callback used when getting the manifest file as a local file descriptor.
360   void NaClManifestFileDidOpen(int32_t pp_error);
361
362   // Processes the JSON manifest string and starts loading the nexe.
363   void ProcessNaClManifest(const nacl::string& manifest_json);
364
365   // Parses the JSON in |manifest_json| and retains a Manifest in
366   // |manifest_| for use by subsequent resource lookups.
367   // On success, |true| is returned and |manifest_| is updated to
368   // contain a Manifest that is used by SelectNexeURLFromManifest.
369   // On failure, |false| is returned, and |manifest_| is unchanged.
370   bool SetManifestObject(const nacl::string& manifest_json,
371                          ErrorInfo* error_info);
372
373   // Logs timing information to a UMA histogram, and also logs the same timing
374   // information divided by the size of the nexe to another histogram.
375   void HistogramStartupTimeSmall(const std::string& name, float dt);
376   void HistogramStartupTimeMedium(const std::string& name, float dt);
377
378   // This NEXE is being used as a content type handler rather than directly by
379   // an HTML document.
380   bool NexeIsContentHandler() const;
381
382   // Callback used when loading a URL for SRPC-based StreamAsFile().
383   void UrlDidOpenForStreamAsFile(int32_t pp_error,
384                                  FileDownloader*& url_downloader,
385                                  PP_CompletionCallback pp_callback);
386
387   // Copy the main service runtime's most recent NaClLog output to the
388   // JavaScript console.  Valid to use only after a crash, e.g., via a
389   // detail level LOG_FATAL NaClLog entry.  If the crash was not due
390   // to a LOG_FATAL this method will do nothing.
391   void CopyCrashLogToJsConsole();
392
393   // Open an app file by requesting a file descriptor from the browser. This
394   // method first checks that the url is for an installed file before making the
395   // request so it won't slow down non-installed file downloads.
396   bool OpenURLFast(const nacl::string& url, FileDownloader* downloader);
397
398   ScriptablePlugin* scriptable_plugin_;
399
400   int argc_;
401   char** argn_;
402   char** argv_;
403
404   // Keep track of the NaCl module subprocess that was spun up in the plugin.
405   NaClSubprocess main_subprocess_;
406
407   nacl::string plugin_base_url_;
408   nacl::string manifest_base_url_;
409   nacl::string manifest_url_;
410   ReadyState nacl_ready_state_;
411   bool nexe_error_reported_;  // error or crash reported
412
413   nacl::DescWrapperFactory* wrapper_factory_;
414
415   std::map<nacl::string, PropertyGetter> property_getters_;
416
417   // File download support.  |nexe_downloader_| can be opened with a specific
418   // callback to run when the file has been downloaded and is opened for
419   // reading.  We use one downloader for all URL downloads to prevent issuing
420   // multiple GETs that might arrive out of order.  For example, this will
421   // prevent a GET of a NaCl manifest while a .nexe GET is pending.  Note that
422   // this will also prevent simultaneous handling of multiple .nexes on a page.
423   FileDownloader nexe_downloader_;
424   pp::CompletionCallbackFactory<Plugin> callback_factory_;
425
426   nacl::scoped_ptr<PnaclCoordinator> pnacl_coordinator_;
427
428   // The manifest dictionary.  Used for looking up resources to be loaded.
429   nacl::scoped_ptr<Manifest> manifest_;
430   // URL processing interface for use in looking up resources in manifests.
431   const pp::URLUtil_Dev* url_util_;
432
433   // A string containing the text description of the last error
434   // produced by this plugin.
435   nacl::string last_error_string_;
436
437   // PPAPI Dev interfaces are disabled by default.
438   bool enable_dev_interfaces_;
439
440   // A flag indicating if the NaCl executable is being loaded from an installed
441   // application.  This flag is used to bucket UMA statistics more precisely to
442   // help determine whether nexe loading problems are caused by networking
443   // issues.  (Installed applications will be loaded from disk.)
444   // Unfortunately, the definition of what it means to be part of an installed
445   // application is a little murky - for example an installed application can
446   // register a mime handler that loads NaCl executables into an arbitrary web
447   // page.  As such, the flag actually means "our best guess, based on the URLs
448   // for NaCl resources that we have seen so far".
449   bool is_installed_;
450
451   // If we get a DidChangeView event before the nexe is loaded, we store it and
452   // replay it to nexe after it's loaded. We need to replay when this View
453   // resource is non-is_null().
454   pp::View view_to_replay_;
455
456   // If we get a HandleDocumentLoad event before the nexe is loaded, we store
457   // it and replay it to nexe after it's loaded. We need to replay when this
458   // URLLoader resource is non-is_null().
459   pp::URLLoader document_load_to_replay_;
460
461   nacl::string mime_type_;
462
463   // Keep track of the FileDownloaders created to fetch urls.
464   std::set<FileDownloader*> url_downloaders_;
465   // Keep track of file descriptors opened by StreamAsFile().
466   // These are owned by the browser.
467   std::map<nacl::string, struct NaClFileInfo> url_file_info_map_;
468
469   // Pending progress events.
470   std::queue<ProgressEvent*> progress_events_;
471
472   // Used for NexeFileDidOpenContinuation
473   int64_t load_start_;
474
475   int64_t init_time_;
476   int64_t ready_time_;
477   size_t nexe_size_;
478
479   // Callback to receive .nexe and .dso download progress notifications.
480   static void UpdateDownloadProgress(
481       PP_Instance pp_instance,
482       PP_Resource pp_resource,
483       int64_t bytes_sent,
484       int64_t total_bytes_to_be_sent,
485       int64_t bytes_received,
486       int64_t total_bytes_to_be_received);
487
488   // Finds the file downloader which owns the given URL loader. This is used
489   // in UpdateDownloadProgress to map a url loader back to the URL being
490   // downloaded.
491   const FileDownloader* FindFileDownloader(PP_Resource url_loader) const;
492
493   int64_t time_of_last_progress_event_;
494
495   const PPB_NaCl_Private* nacl_interface_;
496 };
497
498 }  // namespace plugin
499
500 #endif  // NATIVE_CLIENT_SRC_TRUSTED_PLUGIN_PLUGIN_H_