Home | History | Annotate | Download | only in plugin
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #ifndef NATIVE_CLIENT_SRC_TRUSTED_PLUGIN_PNACL_COORDINATOR_H_
      6 #define NATIVE_CLIENT_SRC_TRUSTED_PLUGIN_PNACL_COORDINATOR_H_
      7 
      8 #include <set>
      9 #include <map>
     10 #include <vector>
     11 
     12 #include "native_client/src/include/nacl_macros.h"
     13 #include "native_client/src/include/nacl_string.h"
     14 #include "native_client/src/shared/platform/nacl_sync_raii.h"
     15 #include "native_client/src/shared/srpc/nacl_srpc.h"
     16 #include "native_client/src/trusted/desc/nacl_desc_wrapper.h"
     17 
     18 #include "ppapi/c/pp_file_info.h"
     19 #include "ppapi/c/trusted/ppb_file_io_trusted.h"
     20 #include "ppapi/cpp/completion_callback.h"
     21 #include "ppapi/cpp/file_io.h"
     22 #include "ppapi/cpp/file_ref.h"
     23 #include "ppapi/cpp/file_system.h"
     24 
     25 #include "ppapi/native_client/src/trusted/plugin/callback_source.h"
     26 #include "ppapi/native_client/src/trusted/plugin/file_downloader.h"
     27 #include "ppapi/native_client/src/trusted/plugin/local_temp_file.h"
     28 #include "ppapi/native_client/src/trusted/plugin/nacl_subprocess.h"
     29 #include "ppapi/native_client/src/trusted/plugin/plugin_error.h"
     30 #include "ppapi/native_client/src/trusted/plugin/pnacl_options.h"
     31 #include "ppapi/native_client/src/trusted/plugin/pnacl_resources.h"
     32 
     33 
     34 namespace plugin {
     35 
     36 class Manifest;
     37 class Plugin;
     38 class PnaclCoordinator;
     39 class PnaclTranslateThread;
     40 class TempFile;
     41 
     42 // A class invoked by Plugin to handle PNaCl client-side translation.
     43 // Usage:
     44 // (1) Invoke the factory method, e.g.,
     45 //     PnaclCoordinator* coord = BitcodeToNative(plugin,
     46 //                                               "http://foo.com/my.pexe",
     47 //                                               pnacl_options,
     48 //                                               TranslateNotifyCallback);
     49 // (2) TranslateNotifyCallback gets invoked when translation is complete.
     50 //     If the translation was successful, the pp_error argument is PP_OK.
     51 //     Other values indicate errors.
     52 // (3) After finish_callback runs, get the file descriptor of the translated
     53 //     nexe, e.g.,
     54 //     fd = coord->ReleaseTranslatedFD();
     55 // (4) Load the nexe from "fd".
     56 // (5) delete coord.
     57 //
     58 // Translation proceeds in two steps:
     59 // (1) llc translates the bitcode in pexe_url_ to an object in obj_file_.
     60 // (2) ld links the object code in obj_file_ and produces a nexe in nexe_file_.
     61 //
     62 // The coordinator proceeds through several states.  They are
     63 // LOAD_TRANSLATOR_BINARIES
     64 //     Complete when ResourcesDidLoad is invoked.
     65 // OPEN_BITCODE_STREAM
     66 //       Complete when BitcodeStreamDidOpen is invoked
     67 // GET_NEXE_FD
     68 //       Get an FD which contains the cached nexe, or is writeable for
     69 //       translation output. Complete when NexeFdDidOpen is called.
     70 //
     71 // If there was a cache hit, go to OPEN_NEXE_FOR_SEL_LDR, otherwise,
     72 // continue streaming the bitcode, and:
     73 // OPEN_TMP_FOR_LLC_TO_LD_COMMUNICATION
     74 //     Complete when ObjectFileDidOpen is invoked.
     75 // OPEN_NEXE_FD_FOR_WRITING
     76 //     Complete when RunTranslate is invoked.
     77 // START_LD_AND_LLC_SUBPROCESS_AND_INITIATE_TRANSLATION
     78 //     Complete when RunTranslate returns.
     79 // TRANSLATION_COMPLETE
     80 //     Complete when TranslateFinished is invoked.
     81 //
     82 // OPEN_NEXE_FOR_SEL_LDR
     83 //   Complete when NexeReadDidOpen is invoked.
     84 class PnaclCoordinator: public CallbackSource<FileStreamData> {
     85  public:
     86   virtual ~PnaclCoordinator();
     87 
     88   // The factory method for translations.
     89   static PnaclCoordinator* BitcodeToNative(
     90       Plugin* plugin,
     91       const nacl::string& pexe_url,
     92       const PnaclOptions& pnacl_options,
     93       const pp::CompletionCallback& translate_notify_callback);
     94 
     95   // Call this to take ownership of the FD of the translated nexe after
     96   // BitcodeToNative has completed (and the finish_callback called).
     97   nacl::DescWrapper* ReleaseTranslatedFD() { return translated_fd_.release(); }
     98 
     99   // Run |translate_notify_callback_| with an error condition that is not
    100   // PPAPI specific.  Also set ErrorInfo report.
    101   void ReportNonPpapiError(PluginErrorCode err, const nacl::string& message);
    102   // Run when faced with a PPAPI error condition. Bring control back to the
    103   // plugin by invoking the |translate_notify_callback_|.
    104   // Also set ErrorInfo report.
    105   void ReportPpapiError(PluginErrorCode err,
    106                         int32_t pp_error, const nacl::string& message);
    107   // Bring control back to the plugin by invoking the
    108   // |translate_notify_callback_|.  This does not set the ErrorInfo report,
    109   // it is assumed that it was already set.
    110   void ExitWithError();
    111 
    112   // Implement FileDownloader's template of the CallbackSource interface.
    113   // This method returns a callback which will be called by the FileDownloader
    114   // to stream the bitcode data as it arrives. The callback
    115   // (BitcodeStreamGotData) passes it to llc over SRPC.
    116   StreamCallback GetCallback();
    117 
    118   // Return a callback that should be notified when |bytes_compiled| bytes
    119   // have been compiled.
    120   pp::CompletionCallback GetCompileProgressCallback(int64_t bytes_compiled);
    121 
    122   // Get the last known load progress.
    123   void GetCurrentProgress(int64_t* bytes_loaded, int64_t* bytes_total);
    124 
    125   // Return true if the total progress to report (w/ progress events) is known.
    126   bool ExpectedProgressKnown() { return expected_pexe_size_ != -1; }
    127 
    128   // Return true if we should delay the progress event reporting.
    129   // This delay approximates:
    130   // - the size of the buffer of bytes sent but not-yet-compiled by LLC.
    131   // - the linking time.
    132   bool ShouldDelayProgressEvent() {
    133     const uint32_t kProgressEventSlopPct = 5;
    134     return ((expected_pexe_size_ - pexe_bytes_compiled_) * 100 /
    135             expected_pexe_size_) < kProgressEventSlopPct;
    136   }
    137 
    138  private:
    139   NACL_DISALLOW_COPY_AND_ASSIGN(PnaclCoordinator);
    140 
    141   // BitcodeToNative is the factory method for PnaclCoordinators.
    142   // Therefore the constructor is private.
    143   PnaclCoordinator(Plugin* plugin,
    144                    const nacl::string& pexe_url,
    145                    const PnaclOptions& pnacl_options,
    146                    const pp::CompletionCallback& translate_notify_callback);
    147 
    148   // Callback for when we know PNaCl is installed.
    149   void DidCheckPnaclInstalled(int32_t pp_error);
    150 
    151   // Callback for when the resource info JSON file has been read.
    152   void ResourceInfoWasRead(int32_t pp_error);
    153 
    154   // Callback for when llc and ld have been downloaded.
    155   void ResourcesDidLoad(int32_t pp_error);
    156 
    157   // Callbacks for temporary file related stages.
    158   // They are invoked from ResourcesDidLoad and proceed in declaration order.
    159   // Invoked when the temporary file system is successfully opened in PPAPI.
    160   void FileSystemDidOpen(int32_t pp_error);
    161   // Invoked after we are sure the PNaCl temporary directory exists.
    162   void DirectoryWasCreated(int32_t pp_error);
    163   // Invoke to issue a GET request for bitcode.
    164   void OpenBitcodeStream();
    165   // Invoked when we've started an URL fetch for the pexe to check for
    166   // caching metadata.
    167   void BitcodeStreamDidOpen(int32_t pp_error);
    168   // Invoked when we've gotten a temp FD for the nexe, either with the nexe
    169   // data, or a writeable fd to save to.
    170   void NexeFdDidOpen(int32_t pp_error);
    171   // Invoked after we have checked the PNaCl cache for a translated version.
    172   void CachedFileDidOpen(int32_t pp_error);
    173   // Invoked when a pexe data chunk arrives (when using streaming translation)
    174   void BitcodeStreamGotData(int32_t pp_error, FileStreamData data);
    175   // Invoked when a pexe data chunk is compiled.
    176   void BitcodeGotCompiled(int32_t pp_error, int64_t bytes_compiled);
    177   // Invoked when the pexe download finishes (using streaming translation)
    178   void BitcodeStreamDidFinish(int32_t pp_error);
    179   // Invoked when the write descriptor for obj_file_ is created.
    180   void ObjectFileDidOpen(int32_t pp_error);
    181   // Once llc and ld nexes have been loaded and the two temporary files have
    182   // been created, this starts the translation.  Translation starts two
    183   // subprocesses, one for llc and one for ld.
    184   void RunTranslate(int32_t pp_error);
    185 
    186   // Invoked when translation is finished.
    187   void TranslateFinished(int32_t pp_error);
    188 
    189   // If the cache is enabled, open a cache file for write, then copy
    190   // the nexe data from temp_nexe_file_ to> cached_nexe_file_.
    191   // Once the copy is done, we commit it to the cache by renaming the
    192   // cache file to the final name.
    193   void CachedNexeOpenedForWrite(int32_t pp_error);
    194   void DidCopyNexeToCachePartial(int32_t pp_error, int32_t num_read_prev,
    195                                  int64_t cur_offset);
    196   void NexeWasCopiedToCache(int32_t pp_error);
    197   // If the copy of the nexe to the not-yet-committed-to-cache file
    198   // failed after partial writes, we attempt to delete the partially written
    199   // file. This callback is invoked when the delete is completed.
    200   void CorruptCacheFileWasDeleted(int32_t delete_pp_error,
    201                                   int32_t orig_pp_error);
    202   // Invoked when the nexe_file_ temporary has been renamed to the nexe name.
    203   void NexeFileWasRenamed(int32_t pp_error);
    204   // Invoked when the read descriptor for nexe_file_ is created.
    205   void NexeReadDidOpen(int32_t pp_error);
    206 
    207   // Keeps track of the pp_error upon entry to TranslateFinished,
    208   // for inspection after cleanup.
    209   int32_t translate_finish_error_;
    210 
    211   // The plugin owning the nexe for which we are doing translation.
    212   Plugin* plugin_;
    213 
    214   pp::CompletionCallback translate_notify_callback_;
    215   // Threadsafety is required to support file lookups.
    216   pp::CompletionCallbackFactory<PnaclCoordinator,
    217                                 pp::ThreadSafeThreadTraits> callback_factory_;
    218 
    219   // Nexe from the final native Link.
    220   nacl::scoped_ptr<nacl::DescWrapper> translated_fd_;
    221 
    222   // Translation creates local temporary files.
    223   nacl::scoped_ptr<pp::FileSystem> file_system_;
    224   // The manifest used by resource loading and ld + llc's reverse service
    225   // to look up objects and libraries.
    226   nacl::scoped_ptr<const Manifest> manifest_;
    227   // An auxiliary class that manages downloaded resources (llc and ld nexes).
    228   nacl::scoped_ptr<PnaclResources> resources_;
    229 
    230   // State used for querying the temporary directory.
    231   nacl::scoped_ptr<pp::FileRef> dir_ref_;
    232 
    233   // The URL for the pexe file.
    234   nacl::string pexe_url_;
    235   // Options for translation.
    236   PnaclOptions pnacl_options_;
    237 
    238   // Object file, produced by the translator and consumed by the linker.
    239   nacl::scoped_ptr<TempFile> obj_file_;
    240   // Translated nexe file, produced by the linker.
    241   nacl::scoped_ptr<TempFile> temp_nexe_file_;
    242   // Cached nexe file, consumed by sel_ldr.  This will be NULL if we do
    243   // not have a writeable cache file.  That is currently the case when
    244   // off_the_record_ is true.
    245   nacl::scoped_ptr<LocalTempFile> cached_nexe_file_;
    246   // True if the new cache flow is enabled. Currently set by an environment
    247   // variable on construction. TODO(dschuff): remove old cache stuff.
    248   bool use_new_cache_;
    249   // Passed to the browser, which sets it to true if there is a translation
    250   // cache hit.
    251   PP_Bool is_cache_hit_;
    252   // Passed to the browser, which sets it to the handle for the nexe file
    253   // (either the translated nexe from the cache, or a temp file to write to).
    254   PP_FileHandle nexe_handle_;
    255 
    256   // Downloader for streaming translation
    257   nacl::scoped_ptr<FileDownloader> streaming_downloader_;
    258 
    259   // Used to report information when errors (PPAPI or otherwise) are reported.
    260   ErrorInfo error_info_;
    261 
    262   // True if an error was already reported, and translate_notify_callback_
    263   // was already run/consumed.
    264   bool error_already_reported_;
    265 
    266   // True if compilation is off_the_record.
    267   bool off_the_record_;
    268 
    269   // State for timing and size information for UMA stats.
    270   int64_t pnacl_init_time_;
    271   int64_t pexe_size_;  // Count as we stream -- will converge to pexe size.
    272   int64_t pexe_bytes_compiled_;  // Count as we compile.
    273   int64_t expected_pexe_size_;   // Expected download total (-1 if unknown).
    274 
    275   // The helper thread used to do translations via SRPC.
    276   // Keep this last in declaration order to ensure the other variables
    277   // haven't been destroyed yet when its destructor runs.
    278   nacl::scoped_ptr<PnaclTranslateThread> translate_thread_;
    279 };
    280 
    281 //----------------------------------------------------------------------
    282 
    283 }  // namespace plugin;
    284 #endif  // NATIVE_CLIENT_SRC_TRUSTED_PLUGIN_PNACL_COORDINATOR_H_
    285