Upstream version 5.34.104.0
[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/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
37 namespace nacl {
38 class DescWrapper;
39 class DescWrapperFactory;
40 }  // namespace nacl
41
42 namespace pp {
43 class URLLoader;
44 class URLUtil_Dev;
45 }
46
47 namespace ppapi_proxy {
48 class BrowserPpp;
49 }
50
51 namespace plugin {
52
53 class ErrorInfo;
54 class Manifest;
55
56 class Plugin : public pp::Instance {
57  public:
58   // Factory method for creation.
59   static Plugin* New(PP_Instance instance);
60
61   // ----- Methods inherited from pp::Instance:
62
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[]);
67
68   // Handles document load, when the plugin is a MIME type handler.
69   virtual bool HandleDocumentLoad(const pp::URLLoader& url_loader);
70
71   // ----- Plugin interface support.
72
73   // Load support.
74   // NaCl module can be loaded given a DescWrapper.
75   //
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
81   // DONE.
82   //
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.
89   //
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);
97
98   // Finish hooking interfaces up, after low-level initialization is
99   // complete.
100   bool LoadNaClModuleContinuationIntern(ErrorInfo* error_info);
101
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);
109
110   // Load support.
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);
118
119   // Returns the argument value for the specified key, or NULL if not found.
120   std::string LookupArgument(const std::string& key) const;
121
122   enum LengthComputable {
123     LENGTH_IS_NOT_COMPUTABLE = 0,
124     LENGTH_IS_COMPUTABLE = 1
125   };
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();
134
135   // Write a text string on the JavaScript console.
136   void AddToConsole(const nacl::string& text);
137
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);
149
150   // Report the error code that sel_ldr produces when starting a nexe.
151   void ReportSelLdrLoadStatus(int status);
152
153   // Report nexe death after load to JS and shut down the proxy.
154   void ReportDeadNexe();
155
156   // URL resolution support.
157   // plugin_base_url is the URL used for resolving relative URLs used in
158   // src="...".
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;
166   }
167
168   // The state of readiness of the plugin.
169   enum ReadyState {
170     // The trusted plugin begins in this ready state.
171     UNSENT = 0,
172     // The manifest file has been requested, but not yet received.
173     OPENED = 1,
174     // This state is unused.
175     HEADERS_RECEIVED = 2,
176     // The manifest file has been received and the nexe successfully requested.
177     LOADING = 3,
178     // The nexe has been loaded and the proxy started, so it is ready for
179     // interaction with the page.
180     DONE = 4
181   };
182   bool nexe_error_reported() const { return nexe_error_reported_; }
183   void set_nexe_error_reported(bool val) {
184     nexe_error_reported_ = val;
185   }
186
187   nacl::DescWrapperFactory* wrapper_factory() const { return wrapper_factory_; }
188
189   // Requests a NaCl manifest download from a |url| relative to the page origin.
190   void RequestNaClManifest(const nacl::string& url);
191
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
194   // sizes return 0.
195   static const uint64_t kUnknownBytes = 0;
196
197   // Called back by CallOnMainThread.  Dispatches the first enqueued progress
198   // event.
199   void DispatchProgressEvent(int32_t result);
200
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);
206
207   // Returns rich information for a file retrieved by StreamAsFile(). This info
208   // contains a file descriptor. The caller must take ownership of this
209   // descriptor.
210   struct NaClFileInfo GetFileInfo(const nacl::string& url);
211
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);
215
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);
220
221   void set_last_error_string(const nacl::string& error);
222
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_; }
234
235   Manifest const* manifest() const { return manifest_.get(); }
236   const pp::URLUtil_Dev* url_util() const { return url_util_; }
237
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);
241
242   const PPB_NaCl_Private* nacl_interface() const { return nacl_interface_; }
243   pp::UMAPrivate& uma_interface() { return uma_interface_; }
244
245  private:
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().
252   ~Plugin();
253
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();
258
259   // Access the service runtime for the main NaCl subprocess.
260   ServiceRuntime* main_service_runtime() const {
261     return main_subprocess_.service_runtime();
262   }
263
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,
271                           int sample,
272                           int maximum,
273                           int out_of_range_replacement);
274   void HistogramEnumerateOsArch(const std::string& sandbox_isa);
275   void HistogramEnumerateLoadStatus(PluginErrorCode error_code,
276                                     bool is_installed);
277   void HistogramEnumerateSelLdrLoadStatus(NaClErrorCode error_code,
278                                           bool is_installed);
279   void HistogramEnumerateManifestIsDataURI(bool is_data_uri);
280   void HistogramHTTPStatusCode(const std::string& name, int status);
281
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);
289
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);
296
297   // Signals that StartSelLdr has finished.
298   void SignalStartSelLdrDone(int32_t pp_error,
299                              bool* started,
300                              ServiceRuntime* service_runtime);
301
302   void LoadNexeAndStart(int32_t pp_error,
303                         nacl::DescWrapper* wrapper,
304                         ServiceRuntime* service_runtime,
305                         const pp::CompletionCallback& crash_cb);
306
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);
312
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);
324
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);
330
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.
336
337   // Callback used when getting the manifest file as a buffer (e.g., data URIs)
338   void NaClManifestBufferReady(int32_t pp_error);
339
340   // Callback used when getting the manifest file as a local file descriptor.
341   void NaClManifestFileDidOpen(int32_t pp_error);
342
343   // Processes the JSON manifest string and starts loading the nexe.
344   void ProcessNaClManifest(const nacl::string& manifest_json);
345
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);
353
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);
358
359   // This NEXE is being used as a content type handler rather than directly by
360   // an HTML document.
361   bool NexeIsContentHandler() const;
362
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);
367
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();
373
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);
378
379   void set_nacl_ready_state(ReadyState state);
380
381   void SetExitStatusOnMainThread(int32_t pp_error, int exit_status);
382
383   std::map<std::string, std::string> args_;
384
385   // Keep track of the NaCl module subprocess that was spun up in the plugin.
386   NaClSubprocess main_subprocess_;
387
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
393
394   nacl::DescWrapperFactory* wrapper_factory_;
395
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_;
404
405   nacl::scoped_ptr<PnaclCoordinator> pnacl_coordinator_;
406
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_;
411
412   // PPAPI Dev interfaces are disabled by default.
413   bool enable_dev_interfaces_;
414
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".
424   bool is_installed_;
425
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_;
430
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_;
435
436   nacl::string mime_type_;
437
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_;
443
444   // Used for NexeFileDidOpenContinuation
445   int64_t load_start_;
446
447   int64_t init_time_;
448   int64_t ready_time_;
449   size_t nexe_size_;
450
451   // Callback to receive .nexe and .dso download progress notifications.
452   static void UpdateDownloadProgress(
453       PP_Instance pp_instance,
454       PP_Resource pp_resource,
455       int64_t bytes_sent,
456       int64_t total_bytes_to_be_sent,
457       int64_t bytes_received,
458       int64_t total_bytes_to_be_received);
459
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
462   // downloaded.
463   const FileDownloader* FindFileDownloader(PP_Resource url_loader) const;
464
465   int64_t time_of_last_progress_event_;
466   int exit_status_;
467
468   const PPB_NaCl_Private* nacl_interface_;
469   pp::UMAPrivate uma_interface_;
470 };
471
472 }  // namespace plugin
473
474 #endif  // NATIVE_CLIENT_SRC_TRUSTED_PLUGIN_PLUGIN_H_