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