Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(407)

Side by Side Diff: src/trusted/plugin/plugin.cc

Issue 7799028: Remove src/trusted/plugin (Closed) Base URL: svn://svn.chromium.org/native_client/trunk/src/native_client
Patch Set: fix gyp file for necessary -I Created 9 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/trusted/plugin/plugin.h ('k') | src/trusted/plugin/plugin.gyp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * Copyright (c) 2011 The Native Client 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
7 #ifdef _MSC_VER
8 // Do not warn about use of std::copy with raw pointers.
9 #pragma warning(disable : 4996)
10 #endif
11
12 #include "native_client/src/trusted/plugin/plugin.h"
13
14 #include <assert.h>
15 #include <fcntl.h>
16 #include <stdarg.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20
21 #include <sys/types.h>
22 #include <sys/stat.h>
23
24 #include <algorithm>
25 #include <deque>
26 #include <string>
27 #include <vector>
28
29 #include "native_client/src/include/nacl_base.h"
30 #include "native_client/src/include/nacl_macros.h"
31 #include "native_client/src/include/nacl_scoped_ptr.h"
32 #include "native_client/src/include/nacl_string.h"
33 #include "native_client/src/include/portability.h"
34 #include "native_client/src/include/portability_io.h"
35 #include "native_client/src/include/portability_string.h"
36 #include "native_client/src/shared/platform/nacl_check.h"
37 #include "native_client/src/shared/platform/nacl_time.h"
38 #include "native_client/src/shared/ppapi_proxy/browser_ppp.h"
39 #include "native_client/src/trusted/desc/nacl_desc_base.h"
40 #include "native_client/src/trusted/desc/nacl_desc_conn_cap.h"
41 #include "native_client/src/trusted/desc/nacl_desc_wrapper.h"
42 #include "native_client/src/trusted/handle_pass/browser_handle.h"
43 #include "native_client/src/trusted/nonnacl_util/sel_ldr_launcher.h"
44 #include "native_client/src/trusted/plugin/browser_interface.h"
45 #include "native_client/src/trusted/plugin/desc_based_handle.h"
46 #include "native_client/src/trusted/plugin/manifest.h"
47 #include "native_client/src/trusted/plugin/nacl_subprocess.h"
48 #include "native_client/src/trusted/plugin/nexe_arch.h"
49 #include "native_client/src/trusted/plugin/plugin_error.h"
50 #include "native_client/src/trusted/plugin/scriptable_handle.h"
51 #include "native_client/src/trusted/plugin/service_runtime.h"
52 #include "native_client/src/trusted/plugin/string_encoding.h"
53 #include "native_client/src/trusted/plugin/utility.h"
54 #include "native_client/src/trusted/service_runtime/include/sys/fcntl.h"
55 #include "native_client/src/trusted/service_runtime/nacl_error_code.h"
56
57 #include "ppapi/c/dev/ppp_find_dev.h"
58 #include "ppapi/c/dev/ppp_printing_dev.h"
59 #include "ppapi/c/dev/ppp_scrollbar_dev.h"
60 #include "ppapi/c/dev/ppp_selection_dev.h"
61 #include "ppapi/c/dev/ppp_widget_dev.h"
62 #include "ppapi/c/dev/ppp_zoom_dev.h"
63 #include "ppapi/c/pp_errors.h"
64 #include "ppapi/c/ppp_input_event.h"
65 #include "ppapi/c/ppp_instance.h"
66 #include "ppapi/c/private/ppb_uma_private.h"
67 #include "ppapi/cpp/dev/find_dev.h"
68 #include "ppapi/cpp/dev/printing_dev.h"
69 #include "ppapi/cpp/dev/scrollbar_dev.h"
70 #include "ppapi/cpp/dev/selection_dev.h"
71 #include "ppapi/cpp/dev/url_util_dev.h"
72 #include "ppapi/cpp/dev/widget_client_dev.h"
73 #include "ppapi/cpp/dev/zoom_dev.h"
74 #include "ppapi/cpp/image_data.h"
75 #include "ppapi/cpp/input_event.h"
76 #include "ppapi/cpp/module.h"
77 #include "ppapi/cpp/rect.h"
78
79 using ppapi_proxy::BrowserPpp;
80
81 namespace plugin {
82
83 namespace {
84
85 bool GetReadyStateProperty(void* obj, SrpcParams* params) {
86 Plugin* plugin = static_cast<Plugin*>(obj);
87 params->outs()[0]->u.ival = plugin->nacl_ready_state();
88 return true;
89 }
90
91 const char* const kTypeAttribute = "type";
92 // The "src" attribute of the <embed> tag. The value is expected to be either
93 // a URL or URI pointing to the manifest file (which is expected to contain
94 // JSON matching ISAs with .nexe URLs).
95 const char* const kSrcManifestAttribute = "src";
96 // The "nacl" attribute of the <embed> tag. We use the value of this attribute
97 // to find the manifest file when NaCl is registered as a plug-in for another
98 // MIME type because the "src" attribute is used to supply us with the resource
99 // of that MIME type that we're supposed to display.
100 const char* const kNaClManifestAttribute = "nacl";
101 // This is a pretty arbitrary limit on the byte size of the NaCl manfest file.
102 // Note that the resulting string object has to have at least one byte extra
103 // for the null termination character.
104 const size_t kNaClManifestMaxFileBytes = 1024 * 1024;
105
106 // URL schemes that we treat in special ways.
107 const char* const kChromeExtensionUriScheme = "chrome-extension";
108 const char* const kDataUriScheme = "data";
109
110 // The key used to find the dictionary nexe URLs in the manifest file.
111 const char* const kNexesKey = "nexes";
112
113 bool GetLastError(void* obj, SrpcParams* params) {
114 NaClSrpcArg** outs = params->outs();
115 PLUGIN_PRINTF(("GetLastError (obj=%p)\n", obj));
116
117 Plugin* plugin = static_cast<Plugin*>(obj);
118 outs[0]->arrays.str = strdup(plugin->last_error_string().c_str());
119 return true;
120 }
121
122 // Up to 20 seconds
123 const int64_t kTimeSmallMin = 1; // in ms
124 const int64_t kTimeSmallMax = 20000; // in ms
125 const uint32_t kTimeSmallBuckets = 100;
126
127 // Up to 3 minutes, 20 seconds
128 const int64_t kTimeMediumMin = 10; // in ms
129 const int64_t kTimeMediumMax = 200000; // in ms
130 const uint32_t kTimeMediumBuckets = 100;
131
132 // Up to 33 minutes.
133 const int64_t kTimeLargeMin = 100; // in ms
134 const int64_t kTimeLargeMax = 2000000; // in ms
135 const uint32_t kTimeLargeBuckets = 100;
136
137 const int64_t kSizeKBMin = 1;
138 const int64_t kSizeKBMax = 512*1024; // very large .nexe
139 const uint32_t kSizeKBBuckets = 100;
140
141 const PPB_UMA_Private* GetUMAInterface() {
142 pp::Module *module = pp::Module::Get();
143 CHECK(module);
144 return static_cast<const PPB_UMA_Private*>(
145 module->GetBrowserInterface(PPB_UMA_PRIVATE_INTERFACE));
146 }
147
148 void HistogramTimeSmall(const std::string& name, int64_t ms) {
149 if (ms < 0) return;
150
151 const PPB_UMA_Private* ptr = GetUMAInterface();
152 if (ptr == NULL) return;
153
154 ptr->HistogramCustomTimes(pp::Var(name).pp_var(),
155 ms,
156 kTimeSmallMin, kTimeSmallMax,
157 kTimeSmallBuckets);
158 }
159
160 void HistogramTimeMedium(const std::string& name, int64_t ms) {
161 if (ms < 0) return;
162
163 const PPB_UMA_Private* ptr = GetUMAInterface();
164 if (ptr == NULL) return;
165
166 ptr->HistogramCustomTimes(pp::Var(name).pp_var(),
167 ms,
168 kTimeMediumMin, kTimeMediumMax,
169 kTimeMediumBuckets);
170 }
171
172 void HistogramTimeLarge(const std::string& name, int64_t ms) {
173 if (ms < 0) return;
174
175 const PPB_UMA_Private* ptr = GetUMAInterface();
176 if (ptr == NULL) return;
177
178 ptr->HistogramCustomTimes(pp::Var(name).pp_var(),
179 ms,
180 kTimeLargeMin, kTimeLargeMax,
181 kTimeLargeBuckets);
182 }
183
184 void HistogramSizeKB(const std::string& name, int32_t sample) {
185 if (sample < 0) return;
186
187 const PPB_UMA_Private* ptr = GetUMAInterface();
188 if (ptr == NULL) return;
189
190 ptr->HistogramCustomCounts(pp::Var(name).pp_var(),
191 sample,
192 kSizeKBMin, kSizeKBMax,
193 kSizeKBBuckets);
194 }
195
196 void HistogramEnumerate(const std::string& name, int sample, int maximum,
197 int out_of_range_replacement) {
198 if (sample < 0 || sample >= maximum) {
199 if (out_of_range_replacement < 0)
200 // No replacement for bad input, abort.
201 return;
202 else
203 // Use a specific value to signal a bad input.
204 sample = out_of_range_replacement;
205 }
206 const PPB_UMA_Private* ptr = GetUMAInterface();
207 if (ptr == NULL) return;
208 ptr->HistogramEnumeration(pp::Var(name).pp_var(), sample, maximum);
209 }
210
211 void HistogramEnumerateOsArch(const std::string& sandbox_isa) {
212 enum NaClOSArch {
213 kNaClLinux32 = 0,
214 kNaClLinux64,
215 kNaClLinuxArm,
216 kNaClMac32,
217 kNaClMac64,
218 kNaClMacArm,
219 kNaClWin32,
220 kNaClWin64,
221 kNaClWinArm,
222 kNaClOSArchMax
223 };
224
225 NaClOSArch os_arch = kNaClOSArchMax;
226 #if NACL_LINUX
227 os_arch = kNaClLinux32;
228 #elif NACL_OSX
229 os_arch = kNaClMac32;
230 #elif NACL_WINDOWS
231 os_arch = kNaClWin32;
232 #endif
233
234 if (sandbox_isa == "x86-64")
235 os_arch = static_cast<NaClOSArch>(os_arch + 1);
236 if (sandbox_isa == "arm")
237 os_arch = static_cast<NaClOSArch>(os_arch + 2);
238
239 HistogramEnumerate("NaCl.Client.OSArch", os_arch, kNaClOSArchMax, -1);
240 }
241
242 void HistogramEnumerateLoadStatus(PluginErrorCode error_code) {
243 HistogramEnumerate("NaCl.LoadStatus.Plugin", error_code, ERROR_MAX,
244 ERROR_UNKNOWN);
245 }
246
247 void HistogramEnumerateSelLdrLoadStatus(NaClErrorCode error_code) {
248 HistogramEnumerate("NaCl.LoadStatus.SelLdr", error_code, NACL_ERROR_CODE_MAX,
249 LOAD_STATUS_UNKNOWN);
250 }
251
252 void HistogramEnumerateManifestIsDataURI(bool is_data_uri) {
253 HistogramEnumerate("NaCl.Manifest.IsDataURI", is_data_uri, 2, -1);
254 }
255
256 // Derive a class from pp::Find_Dev to forward PPP_Find_Dev calls to
257 // the plugin.
258 class FindAdapter : public pp::Find_Dev {
259 public:
260 explicit FindAdapter(Plugin* plugin)
261 : pp::Find_Dev(plugin),
262 plugin_(plugin) {
263 BrowserPpp* proxy = plugin_->ppapi_proxy();
264 CHECK(proxy != NULL);
265 ppp_find_ = static_cast<const PPP_Find_Dev*>(
266 proxy->GetPluginInterface(PPP_FIND_DEV_INTERFACE));
267 }
268
269 bool StartFind(const std::string& text, bool case_sensitive) {
270 if (ppp_find_ != NULL) {
271 PP_Bool pp_success =
272 ppp_find_->StartFind(plugin_->pp_instance(),
273 text.c_str(),
274 PP_FromBool(case_sensitive));
275 return pp_success == PP_TRUE;
276 }
277 return false;
278 }
279
280 void SelectFindResult(bool forward) {
281 if (ppp_find_ != NULL) {
282 ppp_find_->SelectFindResult(plugin_->pp_instance(),
283 PP_FromBool(forward));
284 }
285 }
286
287 void StopFind() {
288 if (ppp_find_ != NULL)
289 ppp_find_->StopFind(plugin_->pp_instance());
290 }
291
292 private:
293 Plugin* plugin_;
294 const PPP_Find_Dev* ppp_find_;
295
296 NACL_DISALLOW_COPY_AND_ASSIGN(FindAdapter);
297 };
298
299
300 // Derive a class from pp::Printing_Dev to forward PPP_Printing_Dev calls to
301 // the plugin.
302 class PrintingAdapter : public pp::Printing_Dev {
303 public:
304 explicit PrintingAdapter(Plugin* plugin)
305 : pp::Printing_Dev(plugin),
306 plugin_(plugin) {
307 BrowserPpp* proxy = plugin_->ppapi_proxy();
308 CHECK(proxy != NULL);
309 ppp_printing_ = static_cast<const PPP_Printing_Dev*>(
310 proxy->GetPluginInterface(PPP_PRINTING_DEV_INTERFACE));
311 }
312
313 PP_PrintOutputFormat_Dev*
314 QuerySupportedPrintOutputFormats(uint32_t* format_count) {
315 if (ppp_printing_ != NULL) {
316 return ppp_printing_->QuerySupportedFormats(plugin_->pp_instance(),
317 format_count);
318 }
319 *format_count = 0;
320 return NULL;
321 }
322
323 int32_t PrintBegin(const PP_PrintSettings_Dev& print_settings) {
324 if (ppp_printing_ != NULL) {
325 return ppp_printing_->Begin(plugin_->pp_instance(), &print_settings);
326 }
327 return 0;
328 }
329
330 pp::Resource PrintPages(const PP_PrintPageNumberRange_Dev* page_ranges,
331 uint32_t page_range_count) {
332 if (ppp_printing_ != NULL) {
333 PP_Resource image_data = ppp_printing_->PrintPages(plugin_->pp_instance(),
334 page_ranges,
335 page_range_count);
336 return pp::ImageData(pp::ImageData::PassRef(), image_data);
337 }
338 return pp::Resource();
339 }
340
341 void PrintEnd() {
342 if (ppp_printing_ != NULL)
343 ppp_printing_->End(plugin_->pp_instance());
344 }
345
346 private:
347 Plugin* plugin_;
348 const PPP_Printing_Dev* ppp_printing_;
349
350 NACL_DISALLOW_COPY_AND_ASSIGN(PrintingAdapter);
351 };
352
353
354 // Derive a class from pp::Selection_Dev to forward PPP_Selection_Dev calls to
355 // the plugin.
356 class SelectionAdapter : public pp::Selection_Dev {
357 public:
358 explicit SelectionAdapter(Plugin* plugin)
359 : pp::Selection_Dev(plugin),
360 plugin_(plugin) {
361 BrowserPpp* proxy = plugin_->ppapi_proxy();
362 CHECK(proxy != NULL);
363 ppp_selection_ = static_cast<const PPP_Selection_Dev*>(
364 proxy->GetPluginInterface(PPP_SELECTION_DEV_INTERFACE));
365 }
366
367 pp::Var GetSelectedText(bool html) {
368 if (ppp_selection_ != NULL) {
369 PP_Var var = ppp_selection_->GetSelectedText(plugin_->pp_instance(),
370 PP_FromBool(html));
371 return pp::Var(pp::Var::PassRef(), var);
372 }
373 return pp::Var();
374 }
375
376 private:
377 Plugin* plugin_;
378 const PPP_Selection_Dev* ppp_selection_;
379
380 NACL_DISALLOW_COPY_AND_ASSIGN(SelectionAdapter);
381 };
382
383
384 // Derive a class from pp::WidgetClient_Dev to forward PPP_Widget_Dev
385 // and PPP_Scrollbar_Dev calls to the plugin.
386 class WidgetClientAdapter : public pp::WidgetClient_Dev {
387 public:
388 explicit WidgetClientAdapter(Plugin* plugin)
389 : pp::WidgetClient_Dev(plugin),
390 plugin_(plugin) {
391 BrowserPpp* proxy = plugin_->ppapi_proxy();
392 CHECK(proxy != NULL);
393 ppp_widget_ = static_cast<const PPP_Widget_Dev*>(
394 proxy->GetPluginInterface(PPP_WIDGET_DEV_INTERFACE));
395 ppp_scrollbar_ = static_cast<const PPP_Scrollbar_Dev*>(
396 proxy->GetPluginInterface(PPP_SCROLLBAR_DEV_INTERFACE));
397 }
398
399 void InvalidateWidget(pp::Widget_Dev widget, const pp::Rect& dirty_rect) {
400 if (ppp_widget_ != NULL) {
401 ppp_widget_->Invalidate(plugin_->pp_instance(),
402 widget.pp_resource(),
403 &dirty_rect.pp_rect());
404 }
405 }
406
407 void ScrollbarValueChanged(pp::Scrollbar_Dev scrollbar, uint32_t value) {
408 if (ppp_scrollbar_ != NULL) {
409 ppp_scrollbar_->ValueChanged(plugin_->pp_instance(),
410 scrollbar.pp_resource(),
411 value);
412 }
413 }
414
415 void ScrollbarOverlayChanged(pp::Scrollbar_Dev scrollbar, bool overlay) {
416 if (ppp_scrollbar_ != NULL) {
417 ppp_scrollbar_->OverlayChanged(plugin_->pp_instance(),
418 scrollbar.pp_resource(),
419 PP_FromBool(overlay));
420 }
421 }
422
423 private:
424 Plugin* plugin_;
425 const PPP_Widget_Dev* ppp_widget_;
426 const PPP_Scrollbar_Dev* ppp_scrollbar_;
427
428 NACL_DISALLOW_COPY_AND_ASSIGN(WidgetClientAdapter);
429 };
430
431
432 // Derive a class from pp::Zoom_Dev to forward PPP_Zoom_Dev calls to
433 // the plugin.
434 class ZoomAdapter : public pp::Zoom_Dev {
435 public:
436 explicit ZoomAdapter(Plugin* plugin)
437 : pp::Zoom_Dev(plugin),
438 plugin_(plugin) {
439 BrowserPpp* proxy = plugin_->ppapi_proxy();
440 CHECK(proxy != NULL);
441 ppp_zoom_ = static_cast<const PPP_Zoom_Dev*>(
442 proxy->GetPluginInterface(PPP_ZOOM_DEV_INTERFACE));
443 }
444
445 void Zoom(double factor, bool text_only) {
446 if (ppp_zoom_ != NULL) {
447 ppp_zoom_->Zoom(plugin_->pp_instance(),
448 factor,
449 PP_FromBool(text_only));
450 }
451 }
452
453 private:
454 Plugin* plugin_;
455 const PPP_Zoom_Dev* ppp_zoom_;
456
457 NACL_DISALLOW_COPY_AND_ASSIGN(ZoomAdapter);
458 };
459
460 } // namespace
461
462 bool Plugin::ExperimentalJavaScriptApisAreEnabled() {
463 return getenv("NACL_ENABLE_EXPERIMENTAL_JAVASCRIPT_APIS") != NULL;
464 }
465
466 static int const kAbiHeaderBuffer = 256; // must be at least EI_ABIVERSION + 1
467
468 void Plugin::LoadMethods() {
469 PLUGIN_PRINTF(("Plugin::LoadMethods ()\n"));
470 // Properties implemented by Plugin.
471 AddPropertyGet(GetReadyStateProperty, "readyState", "i");
472 }
473
474 bool Plugin::HasMethod(uintptr_t method_id, CallType call_type) {
475 PLUGIN_PRINTF(("Plugin::HasMethod (method_id=%x) = ",
476 static_cast<int>(method_id)));
477 if (GetMethodInfo(method_id, call_type)) {
478 PLUGIN_PRINTF(("true\n"));
479 return true;
480 }
481 if (!ExperimentalJavaScriptApisAreEnabled()) {
482 PLUGIN_PRINTF(("false\n"));
483 return false;
484 }
485 if (call_type != METHOD_CALL) {
486 // SRPC nexes can only export methods.
487 PLUGIN_PRINTF(("false\n"));
488 return false;
489 }
490 bool has_method = main_subprocess_.HasMethod(method_id);
491 PLUGIN_PRINTF(("%s\n", (has_method ? "true" : "false")));
492 return has_method;
493 }
494
495 bool Plugin::InitParams(uintptr_t method_id,
496 CallType call_type,
497 SrpcParams* params) {
498 MethodInfo* method_info = GetMethodInfo(method_id, call_type);
499 PLUGIN_PRINTF(("Plugin::InitParams (id=%"NACL_PRIxPTR", method_info=%p)\n",
500 method_id, method_info));
501 if (NULL != method_info) {
502 return params->Init(method_info->ins(), method_info->outs());
503 }
504 if (!ExperimentalJavaScriptApisAreEnabled()) {
505 return false;
506 }
507 if (call_type != METHOD_CALL) {
508 // SRPC nexes can only export methods.
509 return false;
510 }
511 return main_subprocess_.InitParams(method_id, params);
512 }
513
514 bool Plugin::Invoke(uintptr_t method_id,
515 CallType call_type,
516 SrpcParams* params) {
517 MethodInfo* method_info = GetMethodInfo(method_id, call_type);
518
519 if (NULL != method_info && NULL != method_info->function_ptr()) {
520 return method_info->function_ptr()(static_cast<void*>(this), params);
521 }
522 if (!ExperimentalJavaScriptApisAreEnabled()) {
523 return false;
524 }
525 if (call_type != METHOD_CALL) {
526 // SRPC nexes can only export methods.
527 return false;
528 }
529 return main_subprocess_.Invoke(method_id, params);
530 }
531
532 bool Plugin::Init(BrowserInterface* browser_interface,
533 int argc,
534 char* argn[],
535 char* argv[]) {
536 PLUGIN_PRINTF(("Plugin::Init (instance=%p)\n", static_cast<void*>(this)));
537
538 browser_interface_ = browser_interface;
539 // Remember the embed/object argn/argv pairs.
540 argn_ = new(std::nothrow) char*[argc];
541 argv_ = new(std::nothrow) char*[argc];
542 argc_ = 0;
543 for (int i = 0; i < argc; ++i) {
544 if (NULL != argn_ && NULL != argv_) {
545 argn_[argc_] = strdup(argn[i]);
546 argv_[argc_] = strdup(argv[i]);
547 if (NULL == argn_[argc_] || NULL == argv_[argc_]) {
548 // Give up on passing arguments.
549 free(argn_[argc_]);
550 free(argv_[argc_]);
551 continue;
552 }
553 ++argc_;
554 }
555 }
556 // TODO(sehr): this leaks strings if there is a subsequent failure.
557
558 // Set up the factory used to produce DescWrappers.
559 wrapper_factory_ = new nacl::DescWrapperFactory();
560 if (NULL == wrapper_factory_) {
561 return false;
562 }
563 PLUGIN_PRINTF(("Plugin::Init (wrapper_factory=%p)\n",
564 static_cast<void*>(wrapper_factory_)));
565
566 // Set up the scriptable methods for the plugin.
567 LoadMethods();
568
569 PLUGIN_PRINTF(("Plugin::Init (return 1)\n"));
570 // Return success.
571 return true;
572 }
573
574 void Plugin::ShutDownSubprocesses() {
575 PLUGIN_PRINTF(("Plugin::ShutDownSubprocesses (this=%p)\n",
576 static_cast<void*>(this)));
577 PLUGIN_PRINTF(("Plugin::ShutDownSubprocesses (%s)\n",
578 main_subprocess_.detailed_description().c_str()));
579
580 // Shutdown service runtime. This must be done before all other calls so
581 // they don't block forever when waiting for the upcall thread to exit.
582 main_subprocess_.Shutdown();
583 for (size_t i = 0; i < nacl_subprocesses_.size(); ++i) {
584 PLUGIN_PRINTF(("Plugin::ShutDownSubprocesses (%s)\n",
585 nacl_subprocesses_[i]->detailed_description().c_str()));
586 delete nacl_subprocesses_[i];
587 }
588 nacl_subprocesses_.clear();
589
590 PLUGIN_PRINTF(("Plugin::ShutDownSubprocess (this=%p, return)\n",
591 static_cast<void*>(this)));
592 }
593
594 bool Plugin::LoadNaClModuleCommon(nacl::DescWrapper* wrapper,
595 NaClSubprocess* subprocess,
596 ErrorInfo* error_info,
597 pp::CompletionCallback init_done_cb) {
598 ServiceRuntime* new_service_runtime = new(std::nothrow) ServiceRuntime(
599 this,
600 init_done_cb);
601 subprocess->set_service_runtime(new_service_runtime);
602 PLUGIN_PRINTF(("Plugin::LoadNaClModuleCommon (service_runtime=%p)\n",
603 static_cast<void*>(new_service_runtime)));
604 if (NULL == new_service_runtime) {
605 error_info->SetReport(ERROR_SEL_LDR_INIT,
606 "sel_ldr init failure " + subprocess->description());
607 return false;
608 }
609
610 bool service_runtime_started =
611 new_service_runtime->Start(wrapper, error_info);
612 PLUGIN_PRINTF(("Plugin::LoadNaClModuleCommon (service_runtime_started=%d)\n",
613 service_runtime_started));
614 if (!service_runtime_started) {
615 return false;
616 }
617 return true;
618 }
619
620 bool Plugin::StartSrpcServicesCommon(NaClSubprocess* subprocess,
621 ErrorInfo* error_info) {
622 if (!subprocess->StartSrpcServices()) {
623 error_info->SetReport(ERROR_SRPC_CONNECTION_FAIL,
624 "SRPC connection failure for " +
625 subprocess->description());
626 return false;
627 }
628 PLUGIN_PRINTF(("Plugin::StartSrpcServicesCommon (established srpc_client "
629 "%p)\n",
630 static_cast<void*>(subprocess->srpc_client())));
631 return true;
632 }
633
634 bool Plugin::StartSrpcServices(NaClSubprocess* subprocess,
635 ErrorInfo* error_info) {
636 if (!StartSrpcServicesCommon(subprocess, error_info)) {
637 return false;
638 }
639 // TODO(jvoung): This next bit is likely not needed...
640 // If StartSrpcServices is only in the JS API that is just for SRPC nexes
641 // (namely __startSrpcServices), then attempts to start the JS proxy
642 // will fail anyway?
643 // If that is the case, by removing the following line,
644 // the StartSrpcServices == StartSrpcServicesCommon.
645 // We still need this function though, to launch helper SRPC nexes within
646 // the plugin.
647 return StartJSObjectProxy(subprocess, error_info);
648 }
649
650 bool Plugin::StartJSObjectProxy(NaClSubprocess* subprocess,
651 ErrorInfo* error_info) {
652 if (!subprocess->StartJSObjectProxy(this, error_info)) {
653 // TODO(sehr,polina): rename the function and env var
654 // to ExperimentalJavaScriptApisAreEnabled.
655 if (error_info->error_code() == ERROR_START_PROXY_CHECK_PPP &&
656 ExperimentalJavaScriptApisAreEnabled()) {
657 // It is not an error for the proxy to fail to find PPP methods if
658 // experimental APIs are enabled. This means we have an SRPC nexe.
659 error_info->Reset();
660 } else {
661 return false;
662 }
663 }
664 return true;
665 }
666
667 bool Plugin::LoadNaClModule(nacl::DescWrapper* wrapper,
668 ErrorInfo* error_info,
669 pp::CompletionCallback init_done_cb) {
670 // Before forking a new sel_ldr process, ensure that we do not leak
671 // the ServiceRuntime object for an existing subprocess, and that any
672 // associated listener threads do not go unjoined because if they
673 // outlive the Plugin object, they will not be memory safe.
674 ShutDownSubprocesses();
675 if (!(LoadNaClModuleCommon(wrapper, &main_subprocess_, error_info,
676 init_done_cb))) {
677 return false;
678 }
679 PLUGIN_PRINTF(("Plugin::LoadNaClModule (%s)\n",
680 main_subprocess_.detailed_description().c_str()));
681 return true;
682 }
683
684 bool Plugin::LoadNaClModuleContinuationIntern(ErrorInfo* error_info) {
685 if (!(StartSrpcServicesCommon(&main_subprocess_, error_info)
686 && StartJSObjectProxy(&main_subprocess_, error_info))) {
687 return false;
688 }
689 PLUGIN_PRINTF(("Plugin::LoadNaClModule (%s)\n",
690 main_subprocess_.detailed_description().c_str()));
691 return true;
692 }
693
694 NaClSubprocessId Plugin::LoadHelperNaClModule(nacl::DescWrapper* wrapper,
695 ErrorInfo* error_info) {
696 NaClSubprocessId next_id = next_nacl_subprocess_id();
697 nacl::scoped_ptr<NaClSubprocess> nacl_subprocess(
698 new(std::nothrow) NaClSubprocess(next_id, NULL, NULL));
699 if (NULL == nacl_subprocess.get()) {
700 error_info->SetReport(ERROR_SEL_LDR_INIT,
701 "unable to allocate helper subprocess.");
702 return kInvalidNaClSubprocessId;
703 }
704
705 if (!(LoadNaClModuleCommon(wrapper, nacl_subprocess.get(), error_info,
706 pp::BlockUntilComplete())
707 // We need not wait for the init_done callback. We can block
708 // here in StartSrpcServicesCommon, since helper NaCl modules
709 // are spawned from a private thread.
710 //
711 // NB: More refactoring might be needed, however, if helper
712 // NaCl modules have their own manifest. Currently the
713 // manifest is a per-plugin-instance object, not a per
714 // NaClSubprocess object.
715 && StartSrpcServicesCommon(nacl_subprocess.get(), error_info))) {
716 return kInvalidNaClSubprocessId;
717 }
718
719 PLUGIN_PRINTF(("Plugin::LoadHelperNaClModule (%s)\n",
720 nacl_subprocess.get()->detailed_description().c_str()));
721
722 nacl_subprocesses_.push_back(nacl_subprocess.release());
723 return next_id;
724 }
725
726 char* Plugin::LookupArgument(const char* key) {
727 char** keys = argn();
728 for (int ii = 0, len = argc(); ii < len; ++ii) {
729 if (!strcmp(keys[ii], key)) {
730 return argv()[ii];
731 }
732 }
733 return NULL;
734 }
735
736 void Plugin::AddPropertyGet(RpcFunction function_ptr,
737 const char* name,
738 const char* outs) {
739 uintptr_t method_id = browser_interface()->StringToIdentifier(name);
740 PLUGIN_PRINTF(("Plugin::AddPropertyGet (name='%s', id=%"
741 NACL_PRIxPTR")\n", name, method_id));
742 MethodInfo* new_method = new MethodInfo(function_ptr, name, "", outs);
743 property_get_methods_.AddMethod(method_id, new_method);
744 }
745
746 MethodInfo* Plugin::GetMethodInfo(uintptr_t method_id, CallType call_type) {
747 MethodInfo* method_info = NULL;
748 switch (call_type) {
749 case PROPERTY_GET:
750 method_info = property_get_methods_.GetMethod(method_id);
751 break;
752 case PROPERTY_SET:
753 case METHOD_CALL:
754 break;
755 }
756 PLUGIN_PRINTF(("Plugin::GetMethodInfo (id=%"NACL_PRIxPTR", "
757 "return %p)\n", method_id, static_cast<void*>(method_info)));
758 return method_info;
759 }
760
761 class ProgressEvent {
762 public:
763 ProgressEvent(const char* event_type,
764 Plugin::LengthComputable length_computable,
765 uint64_t loaded_bytes,
766 uint64_t total_bytes) :
767 event_type_(event_type),
768 length_computable_(length_computable),
769 loaded_bytes_(loaded_bytes),
770 total_bytes_(total_bytes) { }
771 const char* event_type() const { return event_type_; }
772 Plugin::LengthComputable length_computable() const {
773 return length_computable_;
774 }
775 uint64_t loaded_bytes() const { return loaded_bytes_; }
776 uint64_t total_bytes() const { return total_bytes_; }
777
778 private:
779 // event_type_ is always passed from a string literal, so ownership is
780 // not taken. Hence it does not need to be deleted when ProgressEvent is
781 // destroyed.
782 const char* event_type_;
783 Plugin::LengthComputable length_computable_;
784 uint64_t loaded_bytes_;
785 uint64_t total_bytes_;
786 };
787
788 const char* const Plugin::kNaClMIMEType = "application/x-nacl";
789
790 bool Plugin::IsForeignMIMEType() const {
791 return
792 !mime_type().empty() &&
793 mime_type() != kNaClMIMEType;
794 }
795
796
797 Plugin* Plugin::New(PP_Instance pp_instance) {
798 PLUGIN_PRINTF(("Plugin::New (pp_instance=%"NACL_PRId32")\n", pp_instance));
799 #if NACL_WINDOWS && !defined(NACL_STANDALONE)
800 if (!NaClHandlePassBrowserCtor()) {
801 return NULL;
802 }
803 #endif
804 Plugin* plugin = new(std::nothrow) Plugin(pp_instance);
805 PLUGIN_PRINTF(("Plugin::New (plugin=%p)\n", static_cast<void*>(plugin)));
806 if (plugin == NULL) {
807 return NULL;
808 }
809 return plugin;
810 }
811
812
813 // All failures of this function will show up as "Missing Plugin-in", so
814 // there is no need to log to JS console that there was an initialization
815 // failure. Note that module loading functions will log their own errors.
816 bool Plugin::Init(uint32_t argc, const char* argn[], const char* argv[]) {
817 PLUGIN_PRINTF(("Plugin::Init (argc=%"NACL_PRIu32")\n", argc));
818 HistogramEnumerateOsArch(GetSandboxISA());
819 init_time_ = NaClGetTimeOfDayMicroseconds();
820
821 BrowserInterface* browser_interface = new(std::nothrow) BrowserInterface;
822 if (browser_interface == NULL) {
823 return false;
824 }
825 ScriptableHandle* handle = ScriptableHandle::NewPlugin(this);
826 if (handle == NULL) {
827 return false;
828 }
829 set_scriptable_handle(handle);
830 PLUGIN_PRINTF(("Plugin::Init (scriptable_handle=%p)\n",
831 static_cast<void*>(scriptable_handle())));
832 url_util_ = pp::URLUtil_Dev::Get();
833 if (url_util_ == NULL) {
834 return false;
835 }
836 PLUGIN_PRINTF(("Plugin::Init (url_util_=%p)\n",
837 static_cast<const void*>(url_util_)));
838
839 bool status = Plugin::Init(
840 browser_interface,
841 static_cast<int>(argc),
842 // TODO(polina): Can we change the args on our end to be const to
843 // avoid these ugly casts?
844 const_cast<char**>(argn),
845 const_cast<char**>(argv));
846 if (status) {
847 const char* type_attr = LookupArgument(kTypeAttribute);
848 if (type_attr != NULL) {
849 mime_type_ = nacl::string(type_attr);
850 std::transform(mime_type_.begin(), mime_type_.end(), mime_type_.begin(),
851 tolower);
852 }
853
854 const char* manifest_url = LookupArgument(kSrcManifestAttribute);
855 // If the MIME type is foreign, then 'src' will be the URL for the content
856 // and 'nacl' will be the URL for the manifest.
857 if (IsForeignMIMEType()) {
858 manifest_url = LookupArgument(kNaClManifestAttribute);
859 enable_dev_interface_ = RequiresDevInterface(manifest_url);
860 }
861 // Use the document URL as the base for resolving relative URLs to find the
862 // manifest. This takes into account the setting of <base> tags that
863 // precede the embed/object.
864 CHECK(url_util_ != NULL);
865 pp::Var base_var = url_util_->GetDocumentURL(*this);
866 if (!base_var.is_string()) {
867 PLUGIN_PRINTF(("Plugin::Init (unable to find document url)\n"));
868 return false;
869 }
870 set_plugin_base_url(base_var.AsString());
871 if (manifest_url == NULL) {
872 // TODO(sehr,polina): this should be a hard error when scripting
873 // the src property is no longer allowed.
874 PLUGIN_PRINTF(("Plugin::Init:"
875 " WARNING: no 'src' property, so no manifest loaded.\n"));
876 if (NULL != LookupArgument(kNaClManifestAttribute)) {
877 PLUGIN_PRINTF(("Plugin::Init:"
878 " WARNING: 'nacl' property is incorrect. Use 'src'.\n"));
879 }
880 } else {
881 // Issue a GET for the manifest_url. The manifest file will be parsed to
882 // determine the nexe URL.
883 // Sets src property to full manifest URL.
884 RequestNaClManifest(manifest_url);
885 }
886 }
887
888 // Export a property to allow us to get the last error description.
889 AddPropertyGet(GetLastError, "lastError", "s");
890
891 PLUGIN_PRINTF(("Plugin::Init (status=%d)\n", status));
892 return status;
893 }
894
895
896 Plugin::Plugin(PP_Instance pp_instance)
897 : pp::InstancePrivate(pp_instance),
898 browser_interface_(NULL),
899 scriptable_handle_(NULL),
900 argc_(-1),
901 argn_(NULL),
902 argv_(NULL),
903 main_subprocess_(kMainSubprocessId, NULL, NULL),
904 nacl_ready_state_(UNSENT),
905 wrapper_factory_(NULL),
906 last_error_string_(""),
907 ppapi_proxy_(NULL),
908 enable_dev_interface_(false),
909 replayDidChangeView(false),
910 replayHandleDocumentLoad(false),
911 init_time_(0),
912 ready_time_(0),
913 nexe_size_(0) {
914 PLUGIN_PRINTF(("Plugin::Plugin (this=%p, pp_instance=%"
915 NACL_PRId32")\n", static_cast<void*>(this), pp_instance));
916 NaClSrpcModuleInit();
917 nexe_downloader_.Initialize(this);
918 pnacl_.Initialize(this);
919 callback_factory_.Initialize(this);
920 }
921
922
923 Plugin::~Plugin() {
924 int64_t shutdown_start = NaClGetTimeOfDayMicroseconds();
925
926 PLUGIN_PRINTF(("Plugin::~Plugin (this=%p, scriptable_handle=%p)\n",
927 static_cast<void*>(this),
928 static_cast<void*>(scriptable_handle())));
929
930 // If the proxy has been shutdown before now, it's likely the plugin suffered
931 // an error while loading.
932 if (ppapi_proxy_ != NULL) {
933 HistogramTimeLarge(
934 "NaCl.ModuleUptime.Normal",
935 (shutdown_start - ready_time_) / NACL_MICROS_PER_MILLI);
936 }
937
938 #if NACL_WINDOWS && !defined(NACL_STANDALONE)
939 NaClHandlePassBrowserDtor();
940 #endif
941
942 url_downloaders_.erase(url_downloaders_.begin(), url_downloaders_.end());
943
944 ShutdownProxy();
945 ScriptableHandle* scriptable_handle_ = scriptable_handle();
946 ScriptableHandle::Unref(&scriptable_handle_);
947 NaClSrpcModuleFini();
948
949 // TODO(sehr,polina): We should not need to call ShutDownSubprocesses() here.
950 ShutDownSubprocesses();
951
952 delete wrapper_factory_;
953 delete browser_interface_;
954 delete[] argv_;
955 delete[] argn_;
956
957 HistogramTimeSmall(
958 "NaCl.Perf.ShutdownTime.Total",
959 (NaClGetTimeOfDayMicroseconds() - shutdown_start)
960 / NACL_MICROS_PER_MILLI);
961
962 PLUGIN_PRINTF(("Plugin::~Plugin (this=%p, return)\n",
963 static_cast<void*>(this)));
964 }
965
966
967 void Plugin::DidChangeView(const pp::Rect& position, const pp::Rect& clip) {
968 PLUGIN_PRINTF(("Plugin::DidChangeView (this=%p)\n",
969 static_cast<void*>(this)));
970
971 if (!BrowserPpp::is_valid(ppapi_proxy_)) {
972 // Store this event and replay it when the proxy becomes available.
973 replayDidChangeView = true;
974 replayDidChangeViewPosition = position;
975 replayDidChangeViewClip = clip;
976 return;
977 } else {
978 ppapi_proxy_->ppp_instance_interface()->DidChangeView(
979 pp_instance(), &(position.pp_rect()), &(clip.pp_rect()));
980 }
981 }
982
983
984 void Plugin::DidChangeFocus(bool has_focus) {
985 PLUGIN_PRINTF(("Plugin::DidChangeFocus (this=%p)\n",
986 static_cast<void*>(this)));
987 if (!BrowserPpp::is_valid(ppapi_proxy_)) {
988 return;
989 } else {
990 ppapi_proxy_->ppp_instance_interface()->DidChangeFocus(
991 pp_instance(), PP_FromBool(has_focus));
992 }
993 }
994
995
996 bool Plugin::HandleInputEvent(const pp::InputEvent& event) {
997 PLUGIN_PRINTF(("Plugin::HandleInputEvent (this=%p)\n",
998 static_cast<void*>(this)));
999 if (!BrowserPpp::is_valid(ppapi_proxy_) ||
1000 ppapi_proxy_->ppp_input_event_interface() == NULL) {
1001 return false; // event is not handled here.
1002 } else {
1003 bool handled = PP_ToBool(
1004 ppapi_proxy_->ppp_input_event_interface()->HandleInputEvent(
1005 pp_instance(), event.pp_resource()));
1006 PLUGIN_PRINTF(("Plugin::HandleInputEvent (handled=%d)\n", handled));
1007 return handled;
1008 }
1009 }
1010
1011
1012 bool Plugin::HandleDocumentLoad(const pp::URLLoader& url_loader) {
1013 PLUGIN_PRINTF(("Plugin::HandleDocumentLoad (this=%p)\n",
1014 static_cast<void*>(this)));
1015 if (!BrowserPpp::is_valid(ppapi_proxy_)) {
1016 // Store this event and replay it when the proxy becomes available.
1017 replayHandleDocumentLoad = true;
1018 replayHandleDocumentLoadURLLoader = url_loader;
1019 // Return true so that the browser keeps servicing this loader so we can
1020 // perform requests on it later.
1021 return true;
1022 } else {
1023 return PP_ToBool(
1024 ppapi_proxy_->ppp_instance_interface()->HandleDocumentLoad(
1025 pp_instance(), url_loader.pp_resource()));
1026 }
1027 }
1028
1029
1030 void Plugin::HandleMessage(const pp::Var& message) {
1031 PLUGIN_PRINTF(("Plugin::HandleMessage (this=%p)\n",
1032 static_cast<void*>(this)));
1033 if (BrowserPpp::is_valid(ppapi_proxy_) &&
1034 ppapi_proxy_->ppp_messaging_interface() != NULL) {
1035 ppapi_proxy_->ppp_messaging_interface()->HandleMessage(
1036 pp_instance(), message.pp_var());
1037 }
1038 }
1039
1040
1041 pp::Var Plugin::GetInstanceObject() {
1042 PLUGIN_PRINTF(("Plugin::GetInstanceObject (this=%p)\n",
1043 static_cast<void*>(this)));
1044 // The browser will unref when it discards the var for this object.
1045 ScriptableHandle* handle =
1046 static_cast<ScriptableHandle*>(scriptable_handle()->AddRef());
1047 pp::Var* handle_var = handle->var();
1048 PLUGIN_PRINTF(("Plugin::GetInstanceObject (handle=%p, handle_var=%p)\n",
1049 static_cast<void*>(handle), static_cast<void*>(handle_var)));
1050 return *handle_var; // make a copy
1051 }
1052
1053 void Plugin::HistogramStartupTimeSmall(const std::string& name, float dt) {
1054 if (nexe_size_ > 0) {
1055 float size_in_MB = static_cast<float>(nexe_size_) / (1024.f * 1024.f);
1056 HistogramTimeSmall(name, static_cast<int64_t>(dt));
1057 HistogramTimeSmall(name + "PerMB", static_cast<int64_t>(dt / size_in_MB));
1058 }
1059 }
1060
1061 void Plugin::HistogramStartupTimeMedium(const std::string& name, float dt) {
1062 if (nexe_size_ > 0) {
1063 float size_in_MB = static_cast<float>(nexe_size_) / (1024.f * 1024.f);
1064 HistogramTimeMedium(name, static_cast<int64_t>(dt));
1065 HistogramTimeMedium(name + "PerMB", static_cast<int64_t>(dt / size_in_MB));
1066 }
1067 }
1068
1069 void Plugin::NexeFileDidOpen(int32_t pp_error) {
1070 PLUGIN_PRINTF(("Plugin::NexeFileDidOpen (pp_error=%"NACL_PRId32")\n",
1071 pp_error));
1072 int32_t file_desc = nexe_downloader_.GetPOSIXFileDescriptor();
1073 PLUGIN_PRINTF(("Plugin::NexeFileDidOpen (file_desc=%"NACL_PRId32")\n",
1074 file_desc));
1075 ErrorInfo error_info;
1076 if (pp_error != PP_OK || file_desc == NACL_NO_FILE_DESC) {
1077 if (pp_error == PP_ERROR_ABORTED) {
1078 ReportLoadAbort();
1079 } else {
1080 error_info.SetReport(ERROR_NEXE_LOAD_URL, "could not load nexe url.");
1081 ReportLoadError(error_info);
1082 }
1083 return;
1084 }
1085 int32_t file_desc_ok_to_close = DUP(file_desc);
1086 if (file_desc_ok_to_close == NACL_NO_FILE_DESC) {
1087 error_info.SetReport(ERROR_NEXE_FH_DUP,
1088 "could not duplicate loaded file handle.");
1089 ReportLoadError(error_info);
1090 return;
1091 }
1092 struct stat stat_buf;
1093 if (0 != fstat(file_desc_ok_to_close, &stat_buf)) {
1094 CLOSE(file_desc_ok_to_close);
1095 error_info.SetReport(ERROR_NEXE_STAT, "could not stat nexe file.");
1096 ReportLoadError(error_info);
1097 return;
1098 }
1099 size_t nexe_bytes_read = static_cast<size_t>(stat_buf.st_size);
1100
1101 nexe_size_ = nexe_bytes_read;
1102 HistogramSizeKB("NaCl.Perf.Size.Nexe",
1103 static_cast<int32_t>(nexe_size_ / 1024));
1104 HistogramStartupTimeMedium(
1105 "NaCl.Perf.StartupTime.NexeDownload",
1106 static_cast<float>(nexe_downloader_.TimeSinceOpenMilliseconds()));
1107
1108 // Inform JavaScript that we successfully downloaded the nacl module.
1109 EnqueueProgressEvent("progress",
1110 LENGTH_IS_COMPUTABLE,
1111 nexe_bytes_read,
1112 nexe_bytes_read);
1113
1114 load_start_ = NaClGetTimeOfDayMicroseconds();
1115 nacl::scoped_ptr<nacl::DescWrapper>
1116 wrapper(wrapper_factory()->MakeFileDesc(file_desc_ok_to_close, O_RDONLY));
1117 NaClLog(4, "NexeFileDidOpen: invoking LoadNaClModule\n");
1118 bool was_successful = LoadNaClModule(
1119 wrapper.get(), &error_info,
1120 callback_factory_.NewCallback(&Plugin::NexeFileDidOpenContinuation));
1121
1122 if (!was_successful) {
1123 ReportLoadError(error_info);
1124 }
1125 }
1126
1127 void Plugin::NexeFileDidOpenContinuation(int32_t pp_error) {
1128 ErrorInfo error_info;
1129 bool was_successful;
1130
1131 UNREFERENCED_PARAMETER(pp_error);
1132 NaClLog(4, "Entered NexeFileDidOpenContinuation\n");
1133 NaClLog(4, "NexeFileDidOpenContinuation: invoking"
1134 " LoadNaClModuleContinuationIntern\n");
1135 was_successful = LoadNaClModuleContinuationIntern(&error_info);
1136 if (was_successful) {
1137 NaClLog(4, "NexeFileDidOpenContinuation: success;"
1138 " setting histograms\n");
1139 ready_time_ = NaClGetTimeOfDayMicroseconds();
1140 HistogramStartupTimeSmall(
1141 "NaCl.Perf.StartupTime.LoadModule",
1142 static_cast<float>(ready_time_ - load_start_) / NACL_MICROS_PER_MILLI);
1143 HistogramStartupTimeMedium(
1144 "NaCl.Perf.StartupTime.Total",
1145 static_cast<float>(ready_time_ - init_time_) / NACL_MICROS_PER_MILLI);
1146
1147 ReportLoadSuccess(LENGTH_IS_COMPUTABLE, nexe_size_, nexe_size_);
1148 } else {
1149 NaClLog(4, "NexeFileDidOpenContinuation: failed.");
1150 ReportLoadError(error_info);
1151 }
1152 NaClLog(4, "Leaving NexeFileDidOpenContinuation\n");
1153 }
1154
1155 void Plugin::BitcodeDidTranslate(int32_t pp_error) {
1156 PLUGIN_PRINTF(("Plugin::BitcodeDidTranslate (pp_error=%"NACL_PRId32")\n",
1157 pp_error));
1158 if (pp_error != PP_OK) {
1159 // Error should have been reported by pnacl. Just return.
1160 PLUGIN_PRINTF(("Plugin::BitcodeDidTranslate error in Pnacl\n"));
1161 return;
1162 }
1163 // Inform JavaScript that we successfully translated the bitcode to a nexe.
1164 EnqueueProgressEvent("progress",
1165 LENGTH_IS_NOT_COMPUTABLE,
1166 kUnknownBytes,
1167 kUnknownBytes);
1168 nacl::scoped_ptr<nacl::DescWrapper>
1169 wrapper(pnacl_.ReleaseTranslatedFD());
1170 ErrorInfo error_info;
1171 bool was_successful = LoadNaClModule(
1172 wrapper.get(), &error_info,
1173 callback_factory_.NewCallback(&Plugin::BitcodeDidTranslateContinuation));
1174
1175 if (!was_successful) {
1176 ReportLoadError(error_info);
1177 }
1178 }
1179
1180 void Plugin::BitcodeDidTranslateContinuation(int32_t pp_error) {
1181 ErrorInfo error_info;
1182 bool was_successful = LoadNaClModuleContinuationIntern(&error_info);
1183
1184 NaClLog(4, "Entered BitcodeDidTranslateContinuation\n");
1185 UNREFERENCED_PARAMETER(pp_error);
1186 if (was_successful) {
1187 ReportLoadSuccess(LENGTH_IS_NOT_COMPUTABLE,
1188 kUnknownBytes,
1189 kUnknownBytes);
1190 } else {
1191 ReportLoadError(error_info);
1192 }
1193 }
1194
1195 // Check manifest_url and return whether or not to enable PPAPI Dev interfaces.
1196 // Returning true here will enable the PPAPI Dev interfaces regardless of
1197 // the environment variable NACL_ENABLE_PPAPI_DEV.
1198 bool Plugin::RequiresDevInterface(const nacl::string& manifest_url) {
1199 const char* extensions[] = {
1200 "chrome-extension://acadkphlmlegjaadjagenfimbpphcgnh/", // PDF
1201 };
1202 for (size_t i = 0; i < sizeof(extensions) / sizeof(const char*); ++i) {
1203 if (manifest_url.find(extensions[i]) == 0) {
1204 return true;
1205 }
1206 }
1207 return false;
1208 }
1209
1210 bool Plugin::StartProxiedExecution(NaClSrpcChannel* srpc_channel,
1211 ErrorInfo* error_info) {
1212 PLUGIN_PRINTF(("Plugin::StartProxiedExecution (srpc_channel=%p)\n",
1213 static_cast<void*>(srpc_channel)));
1214
1215 // Log the amound of time that has passed between the trusted plugin being
1216 // initialized and the untrusted plugin being initialized. This is (roughly)
1217 // the cost of using NaCl, in terms of startup time.
1218 HistogramStartupTimeMedium(
1219 "NaCl.Perf.StartupTime.NaClOverhead",
1220 static_cast<float>(NaClGetTimeOfDayMicroseconds() - init_time_)
1221 / NACL_MICROS_PER_MILLI);
1222
1223 // Check that the .nexe exports the PPAPI intialization method.
1224 NaClSrpcService* client_service = srpc_channel->client;
1225 if (NaClSrpcServiceMethodIndex(client_service,
1226 "PPP_InitializeModule:iihs:ii") ==
1227 kNaClSrpcInvalidMethodIndex) {
1228 error_info->SetReport(
1229 ERROR_START_PROXY_CHECK_PPP,
1230 "could not find PPP_InitializeModule() - toolchain version mismatch?");
1231 PLUGIN_PRINTF(("Plugin::StartProxiedExecution (%s)\n",
1232 error_info->message().c_str()));
1233 return false;
1234 }
1235 nacl::scoped_ptr<BrowserPpp> ppapi_proxy(
1236 new(std::nothrow) BrowserPpp(srpc_channel, this));
1237 PLUGIN_PRINTF(("Plugin::StartProxiedExecution (ppapi_proxy=%p)\n",
1238 static_cast<void*>(ppapi_proxy.get())));
1239 if (ppapi_proxy.get() == NULL) {
1240 error_info->SetReport(ERROR_START_PROXY_ALLOC,
1241 "could not allocate proxy memory.");
1242 return false;
1243 }
1244 pp::Module* module = pp::Module::Get();
1245 PLUGIN_PRINTF(("Plugin::StartProxiedExecution (module=%p)\n",
1246 static_cast<void*>(module)));
1247 CHECK(module != NULL); // We could not have gotten past init stage otherwise.
1248 int32_t pp_error =
1249 ppapi_proxy->InitializeModule(module->pp_module(),
1250 module->get_browser_interface());
1251 PLUGIN_PRINTF(("Plugin::StartProxiedExecution (pp_error=%"
1252 NACL_PRId32")\n", pp_error));
1253 if (pp_error != PP_OK) {
1254 error_info->SetReport(ERROR_START_PROXY_MODULE,
1255 "could not initialize module.");
1256 return false;
1257 }
1258 const PPP_Instance* instance_interface =
1259 ppapi_proxy->ppp_instance_interface();
1260 PLUGIN_PRINTF(("Plugin::StartProxiedExecution (ppp_instance=%p)\n",
1261 static_cast<const void*>(instance_interface)));
1262 CHECK(instance_interface != NULL); // Verified on module initialization.
1263 PP_Bool did_create = instance_interface->DidCreate(
1264 pp_instance(),
1265 argc(),
1266 const_cast<const char**>(argn()),
1267 const_cast<const char**>(argv()));
1268 PLUGIN_PRINTF(("Plugin::StartProxiedExecution (did_create=%d)\n",
1269 did_create));
1270 if (did_create == PP_FALSE) {
1271 error_info->SetReport(ERROR_START_PROXY_INSTANCE,
1272 "could not create instance.");
1273 return false;
1274 }
1275
1276 ppapi_proxy_ = ppapi_proxy.release();
1277
1278 // Create PPP* interface adapters to forward calls to .nexe.
1279 find_adapter_.reset(new(std::nothrow) FindAdapter(this));
1280 printing_adapter_.reset(new(std::nothrow) PrintingAdapter(this));
1281 selection_adapter_.reset(new(std::nothrow) SelectionAdapter(this));
1282 widget_client_adapter_.reset(new(std::nothrow) WidgetClientAdapter(this));
1283 zoom_adapter_.reset(new(std::nothrow) ZoomAdapter(this));
1284
1285 // Replay missed events.
1286 if (replayDidChangeView) {
1287 replayDidChangeView = false;
1288 DidChangeView(replayDidChangeViewPosition, replayDidChangeViewClip);
1289 }
1290 if (replayHandleDocumentLoad) {
1291 replayHandleDocumentLoad = false;
1292 HandleDocumentLoad(replayHandleDocumentLoadURLLoader);
1293 // Release our reference on this loader.
1294 replayHandleDocumentLoadURLLoader = pp::URLLoader();
1295 }
1296 bool is_valid_proxy = BrowserPpp::is_valid(ppapi_proxy_);
1297 PLUGIN_PRINTF(("Plugin::StartProxiedExecution (is_valid_proxy=%d)\n",
1298 is_valid_proxy));
1299 if (!is_valid_proxy) {
1300 error_info->SetReport(ERROR_START_PROXY_CRASH,
1301 "instance crashed after creation.");
1302 }
1303 return is_valid_proxy;
1304 }
1305
1306 void Plugin::ReportDeadNexe() {
1307 PLUGIN_PRINTF(("Plugin::ReportDeadNexe\n"));
1308
1309 if (nacl_ready_state() == DONE) { // After loadEnd.
1310 int64_t crash_time = NaClGetTimeOfDayMicroseconds();
1311 // Crashes will be more likely near startup, so use a medium histogram
1312 // instead of a large one.
1313 HistogramTimeMedium(
1314 "NaCl.ModuleUptime.Crash",
1315 (crash_time - ready_time_) / NACL_MICROS_PER_MILLI);
1316
1317 EnqueueProgressEvent("crash",
1318 LENGTH_IS_NOT_COMPUTABLE,
1319 kUnknownBytes,
1320 kUnknownBytes);
1321 CHECK(ppapi_proxy_ != NULL && !ppapi_proxy_->is_valid());
1322 ShutdownProxy();
1323 }
1324 // else LoadNaClModule and NexeFileDidOpen will provide error handling.
1325 // NOTE: not all crashes during load will make it here.
1326 // Those in BrowserPpp::InitializeModule and creation of PPP interfaces
1327 // will just get reported back as PP_ERROR_FAILED.
1328 }
1329
1330 void Plugin::ShutdownProxy() {
1331 PLUGIN_PRINTF(("Plugin::ShutdownProxy (ppapi_proxy=%p)\n",
1332 static_cast<void*>(ppapi_proxy_)));
1333 // We do not call remote PPP_Instance::DidDestroy because the untrusted
1334 // side can no longer take full advantage of mostly asynchronous Pepper
1335 // per-Instance interfaces at this point.
1336 if (BrowserPpp::is_valid(ppapi_proxy_))
1337 ppapi_proxy_->ShutdownModule();
1338 delete ppapi_proxy_;
1339 ppapi_proxy_ = NULL;
1340 }
1341
1342 void Plugin::NaClManifestBufferReady(int32_t pp_error) {
1343 PLUGIN_PRINTF(("Plugin::NaClManifestBufferReady (pp_error=%"
1344 NACL_PRId32")\n", pp_error));
1345 ErrorInfo error_info;
1346 set_manifest_url(nexe_downloader_.url());
1347 if (pp_error != PP_OK) {
1348 if (pp_error == PP_ERROR_ABORTED) {
1349 ReportLoadAbort();
1350 } else {
1351 error_info.SetReport(ERROR_MANIFEST_LOAD_URL,
1352 "could not load manifest url.");
1353 ReportLoadError(error_info);
1354 }
1355 return;
1356 }
1357
1358 const std::deque<char>& buffer = nexe_downloader_.buffer();
1359 size_t buffer_size = buffer.size();
1360 if (buffer_size > kNaClManifestMaxFileBytes) {
1361 error_info.SetReport(ERROR_MANIFEST_TOO_LARGE,
1362 "manifest file too large.");
1363 ReportLoadError(error_info);
1364 return;
1365 }
1366 nacl::scoped_array<char> json_buffer(new char[buffer_size + 1]);
1367 if (json_buffer == NULL) {
1368 error_info.SetReport(ERROR_MANIFEST_MEMORY_ALLOC,
1369 "could not allocate manifest memory.");
1370 ReportLoadError(error_info);
1371 return;
1372 }
1373 std::copy(buffer.begin(), buffer.begin() + buffer_size, &json_buffer[0]);
1374 json_buffer[buffer_size] = '\0';
1375
1376 ProcessNaClManifest(json_buffer.get());
1377 }
1378
1379 void Plugin::NaClManifestFileDidOpen(int32_t pp_error) {
1380 PLUGIN_PRINTF(("Plugin::NaClManifestFileDidOpen (pp_error=%"
1381 NACL_PRId32")\n", pp_error));
1382 HistogramTimeSmall("NaCl.Perf.StartupTime.ManifestDownload",
1383 nexe_downloader_.TimeSinceOpenMilliseconds());
1384 ErrorInfo error_info;
1385 // The manifest file was successfully opened. Set the src property on the
1386 // plugin now, so that the full url is available to error handlers.
1387 set_manifest_url(nexe_downloader_.url());
1388 int32_t file_desc = nexe_downloader_.GetPOSIXFileDescriptor();
1389 PLUGIN_PRINTF(("Plugin::NaClManifestFileDidOpen (file_desc=%"
1390 NACL_PRId32")\n", file_desc));
1391 if (pp_error != PP_OK || file_desc == NACL_NO_FILE_DESC) {
1392 if (pp_error == PP_ERROR_ABORTED) {
1393 ReportLoadAbort();
1394 } else {
1395 error_info.SetReport(ERROR_MANIFEST_LOAD_URL,
1396 "could not load manifest url.");
1397 ReportLoadError(error_info);
1398 }
1399 return;
1400 }
1401 // Duplicate the file descriptor in order to create a FILE stream with it
1402 // that can later be closed without closing the original descriptor. The
1403 // browser will take care of the original descriptor.
1404 int dup_file_desc = DUP(file_desc);
1405 struct stat stat_buf;
1406 if (0 != fstat(dup_file_desc, &stat_buf)) {
1407 CLOSE(dup_file_desc);
1408 error_info.SetReport(ERROR_MANIFEST_STAT,
1409 "could not stat manifest file.");
1410 ReportLoadError(error_info);
1411 return;
1412 }
1413 size_t bytes_to_read = static_cast<size_t>(stat_buf.st_size);
1414 if (bytes_to_read > kNaClManifestMaxFileBytes) {
1415 CLOSE(dup_file_desc);
1416 error_info.SetReport(ERROR_MANIFEST_TOO_LARGE,
1417 "manifest file too large.");
1418 ReportLoadError(error_info);
1419 return;
1420 }
1421 FILE* json_file = fdopen(dup_file_desc, "rb");
1422 PLUGIN_PRINTF(("Plugin::NaClManifestFileDidOpen "
1423 "(dup_file_desc=%"NACL_PRId32", json_file=%p)\n",
1424 dup_file_desc, static_cast<void*>(json_file)));
1425 if (json_file == NULL) {
1426 CLOSE(dup_file_desc);
1427 error_info.SetReport(ERROR_MANIFEST_OPEN,
1428 "could not open manifest file.");
1429 ReportLoadError(error_info);
1430 return;
1431 }
1432 nacl::scoped_array<char> json_buffer(new char[bytes_to_read + 1]);
1433 if (json_buffer == NULL) {
1434 fclose(json_file);
1435 error_info.SetReport(ERROR_MANIFEST_MEMORY_ALLOC,
1436 "could not allocate manifest memory.");
1437 ReportLoadError(error_info);
1438 return;
1439 }
1440 // json_buffer could hold a large enough buffer that the system might need
1441 // multiple reads to fill it, so iterate through reads.
1442 size_t total_bytes_read = 0;
1443 while (0 < bytes_to_read) {
1444 size_t bytes_this_read = fread(&json_buffer[total_bytes_read],
1445 sizeof(char),
1446 bytes_to_read,
1447 json_file);
1448 if (bytes_this_read < bytes_to_read &&
1449 (feof(json_file) || ferror(json_file))) {
1450 PLUGIN_PRINTF(("Plugin::NaClManifestFileDidOpen failed: "
1451 "total_bytes_read=%"NACL_PRIuS" "
1452 "bytes_to_read=%"NACL_PRIuS"\n",
1453 total_bytes_read, bytes_to_read));
1454 fclose(json_file);
1455 error_info.SetReport(ERROR_MANIFEST_READ,
1456 "could not read manifest file.");
1457 ReportLoadError(error_info);
1458 return;
1459 }
1460 total_bytes_read += bytes_this_read;
1461 bytes_to_read -= bytes_this_read;
1462 }
1463 // Once the bytes are read, the FILE is no longer needed, so close it. This
1464 // allows for early returns without leaking the |json_file| FILE object.
1465 fclose(json_file);
1466 // No need to close |file_desc|, that is handled by |nexe_downloader_|.
1467 json_buffer[total_bytes_read] = '\0'; // Force null termination.
1468
1469 ProcessNaClManifest(json_buffer.get());
1470 }
1471
1472 void Plugin::ProcessNaClManifest(const nacl::string& manifest_json) {
1473 HistogramSizeKB("NaCl.Perf.Size.Manifest",
1474 static_cast<int32_t>(manifest_json.length() / 1024));
1475 nacl::string program_url;
1476 bool is_portable;
1477 ErrorInfo error_info;
1478 if (!SetManifestObject(manifest_json, &error_info)) {
1479 ReportLoadError(error_info);
1480 return;
1481 }
1482
1483 if (SelectProgramURLFromManifest(&program_url, &error_info, &is_portable)) {
1484 set_nacl_ready_state(LOADING);
1485 // Inform JavaScript that we found a nexe URL to load.
1486 EnqueueProgressEvent("progress",
1487 LENGTH_IS_NOT_COMPUTABLE,
1488 kUnknownBytes,
1489 kUnknownBytes);
1490 if (is_portable) {
1491 // TODO(jvoung): Do we want to check an ENV var if pnacl is enabled first?
1492 nacl::string llc_url;
1493 nacl::string ld_url;
1494 if (SelectLLCURLFromManifest(&llc_url, &error_info) &&
1495 SelectLDURLFromManifest(&ld_url, &error_info)) {
1496 pp::CompletionCallback translate_callback =
1497 callback_factory_.NewCallback(&Plugin::BitcodeDidTranslate);
1498 // Will always call the callback on success or failure.
1499 pnacl_.BitcodeToNative(program_url,
1500 llc_url,
1501 ld_url,
1502 translate_callback);
1503 return;
1504 }
1505 } else {
1506 pp::CompletionCallback open_callback =
1507 callback_factory_.NewRequiredCallback(&Plugin::NexeFileDidOpen);
1508 // Will always call the callback on success or failure.
1509 CHECK(
1510 nexe_downloader_.Open(program_url, DOWNLOAD_TO_FILE, open_callback));
1511 return;
1512 }
1513 }
1514 // Failed to select the program and/or the translator.
1515 ReportLoadError(error_info);
1516 }
1517
1518 void Plugin::RequestNaClManifest(const nacl::string& url) {
1519 PLUGIN_PRINTF(("Plugin::RequestNaClManifest (url='%s')\n", url.c_str()));
1520 PLUGIN_PRINTF(("Plugin::RequestNaClManifest (plugin base url='%s')\n",
1521 plugin_base_url().c_str()));
1522 // The full URL of the manifest file is relative to the base url.
1523 CHECK(url_util_ != NULL);
1524 pp::Var nmf_resolved_url =
1525 url_util_->ResolveRelativeToURL(plugin_base_url(), pp::Var(url));
1526 if (!nmf_resolved_url.is_string()) {
1527 ErrorInfo error_info;
1528 error_info.SetReport(
1529 ERROR_MANIFEST_RESOLVE_URL,
1530 nacl::string("could not resolve URL \"") + url.c_str() +
1531 "\" relative to \"" + plugin_base_url().c_str() + "\".");
1532 ReportLoadError(error_info);
1533 return;
1534 }
1535 PLUGIN_PRINTF(("Plugin::RequestNaClManifest (resolved url='%s')\n",
1536 nmf_resolved_url.AsString().c_str()));
1537 set_manifest_base_url(nmf_resolved_url.AsString());
1538 set_manifest_url(url);
1539 // Inform JavaScript that a load is starting.
1540 set_nacl_ready_state(OPENED);
1541 EnqueueProgressEvent("loadstart",
1542 LENGTH_IS_NOT_COMPUTABLE,
1543 kUnknownBytes,
1544 kUnknownBytes);
1545 bool is_data_uri = GetUrlScheme(nmf_resolved_url.AsString()) == SCHEME_DATA;
1546 HistogramEnumerateManifestIsDataURI(static_cast<int>(is_data_uri));
1547 if (is_data_uri) {
1548 pp::CompletionCallback open_callback =
1549 callback_factory_.NewRequiredCallback(&Plugin::NaClManifestBufferReady);
1550 // Will always call the callback on success or failure.
1551 CHECK(nexe_downloader_.Open(nmf_resolved_url.AsString(),
1552 DOWNLOAD_TO_BUFFER,
1553 open_callback));
1554 } else {
1555 pp::CompletionCallback open_callback =
1556 callback_factory_.NewRequiredCallback(&Plugin::NaClManifestFileDidOpen);
1557 // Will always call the callback on success or failure.
1558 CHECK(nexe_downloader_.Open(nmf_resolved_url.AsString(),
1559 DOWNLOAD_TO_FILE,
1560 open_callback));
1561 }
1562 }
1563
1564
1565 bool Plugin::SetManifestObject(const nacl::string& manifest_json,
1566 ErrorInfo* error_info) {
1567 PLUGIN_PRINTF(("Plugin::SetManifestObject(): manifest_json='%s'.\n",
1568 manifest_json.c_str()));
1569 if (error_info == NULL)
1570 return false;
1571 manifest_.reset(
1572 new Manifest(url_util_, manifest_base_url(), GetSandboxISA()));
1573 if (!manifest_->Init(manifest_json, error_info)) {
1574 return false;
1575 }
1576 return true;
1577 }
1578
1579 bool Plugin::SelectProgramURLFromManifest(nacl::string* result,
1580 ErrorInfo* error_info,
1581 bool* is_portable) {
1582 const nacl::string sandbox_isa(GetSandboxISA());
1583 PLUGIN_PRINTF(("Plugin::SelectProgramURLFromManifest(): sandbox='%s'.\n",
1584 sandbox_isa.c_str()));
1585 if (result == NULL || error_info == NULL || manifest_ == NULL)
1586 return false;
1587 return manifest_->GetProgramURL(result, error_info, is_portable);
1588 }
1589
1590 // TODO(jvoung): get rid of these when we have a better hosting solution
1591 // for PNaCl's nexes.
1592 bool Plugin::SelectLLCURLFromManifest(nacl::string* result,
1593 ErrorInfo* error_info) {
1594 PLUGIN_PRINTF(("Plugin::SelectLLCURLFromManifest()\n"));
1595 if (result == NULL || error_info == NULL || manifest_ == NULL)
1596 return false;
1597 return manifest_->GetLLCURL(result, error_info);
1598 }
1599
1600 bool Plugin::SelectLDURLFromManifest(nacl::string* result,
1601 ErrorInfo* error_info) {
1602 PLUGIN_PRINTF(("Plugin::SelectLDURLFromManifest()\n"));
1603 if (result == NULL || error_info == NULL || manifest_ == NULL)
1604 return false;
1605 return manifest_->GetLDURL(result, error_info);
1606 }
1607 // end TODO(jvoung)
1608
1609
1610 void Plugin::UrlDidOpenForStreamAsFile(int32_t pp_error,
1611 FileDownloader*& url_downloader,
1612 PP_CompletionCallback callback) {
1613 PLUGIN_PRINTF(("Plugin::UrlDidOpen (pp_error=%"NACL_PRId32
1614 ", url_downloader=%p)\n", pp_error,
1615 static_cast<void*>(url_downloader)));
1616 url_downloaders_.erase(url_downloader);
1617 nacl::scoped_ptr<FileDownloader> scoped_url_downloader(url_downloader);
1618 int32_t file_desc = scoped_url_downloader->GetPOSIXFileDescriptor();
1619
1620 if (pp_error != PP_OK) {
1621 PP_RunCompletionCallback(&callback, pp_error);
1622 } else if (file_desc > NACL_NO_FILE_DESC) {
1623 url_fd_map_[url_downloader->url_to_open()] = file_desc;
1624 PP_RunCompletionCallback(&callback, PP_OK);
1625 } else {
1626 PP_RunCompletionCallback(&callback, PP_ERROR_FAILED);
1627 }
1628 }
1629
1630 int32_t Plugin::GetPOSIXFileDesc(const nacl::string& url) {
1631 PLUGIN_PRINTF(("Plugin::GetFileDesc (url=%s)\n", url.c_str()));
1632 int32_t file_desc_ok_to_close = NACL_NO_FILE_DESC;
1633 std::map<nacl::string, int32_t>::iterator it = url_fd_map_.find(url);
1634 if (it != url_fd_map_.end())
1635 file_desc_ok_to_close = DUP(it->second);
1636 return file_desc_ok_to_close;
1637 }
1638
1639
1640 bool Plugin::StreamAsFile(const nacl::string& url,
1641 PP_CompletionCallback callback) {
1642 PLUGIN_PRINTF(("Plugin::StreamAsFile (url='%s')\n", url.c_str()));
1643 FileDownloader* downloader = new FileDownloader();
1644 downloader->Initialize(this);
1645 url_downloaders_.insert(downloader);
1646 pp::CompletionCallback open_callback =
1647 callback_factory_.NewRequiredCallback(
1648 &Plugin::UrlDidOpenForStreamAsFile, downloader, callback);
1649 // Untrusted loads are always relative to the page's origin.
1650 CHECK(url_util_ != NULL);
1651 pp::Var resolved_url =
1652 url_util_->ResolveRelativeToURL(pp::Var(plugin_base_url()), url);
1653 if (!resolved_url.is_string()) {
1654 PLUGIN_PRINTF(("Plugin::StreamAsFile: "
1655 "could not resolve url \"%s\" relative to plugin \"%s\".",
1656 url.c_str(),
1657 plugin_base_url().c_str()));
1658 return false;
1659 }
1660 // If true, will always call the callback on success or failure.
1661 return downloader->Open(url, DOWNLOAD_TO_FILE, open_callback);
1662 }
1663
1664 #ifndef HACK_FOR_MACOS_HANG_REMOVED
1665 // The following is needed to avoid a plugin startup hang in the
1666 // MacOS "chrome_browser_tests under gyp" stage.
1667 // TODO(sehr,mseaborn): remove this hack.
1668 void (plugin::Plugin::*pmem)(int32_t,
1669 plugin::FileDownloader*&,
1670 pp::VarPrivate&);
1671 void Plugin::XYZZY(const nacl::string& url,
1672 pp::VarPrivate js_callback) {
1673 UNREFERENCED_PARAMETER(url);
1674 UNREFERENCED_PARAMETER(js_callback);
1675 pp::CompletionCallback open_callback =
1676 callback_factory_.NewRequiredCallback(pmem,
1677 reinterpret_cast<plugin::FileDownloader*>(NULL),
1678 js_callback);
1679 }
1680 #endif // HACK_FOR_MACOS_HANG_REMOVED
1681
1682
1683 void Plugin::ReportLoadSuccess(LengthComputable length_computable,
1684 uint64_t loaded_bytes,
1685 uint64_t total_bytes) {
1686 // Set the readyState attribute to indicate loaded.
1687 set_nacl_ready_state(DONE);
1688 // Inform JavaScript that loading was successful and is complete.
1689 EnqueueProgressEvent("load", length_computable, loaded_bytes, total_bytes);
1690 EnqueueProgressEvent("loadend", length_computable, loaded_bytes, total_bytes);
1691
1692 // UMA
1693 HistogramEnumerateLoadStatus(ERROR_LOAD_SUCCESS);
1694 }
1695
1696
1697 // TODO(ncbray): report UMA stats
1698 void Plugin::ReportLoadError(const ErrorInfo& error_info) {
1699 PLUGIN_PRINTF(("Plugin::ReportLoadError (error='%s')\n",
1700 error_info.message().c_str()));
1701 // Set the readyState attribute to indicate we need to start over.
1702 set_nacl_ready_state(DONE);
1703 // Report an error in lastError and on the JavaScript console.
1704 nacl::string message = nacl::string("NaCl module load failed: ") +
1705 error_info.message();
1706 set_last_error_string(message);
1707 browser_interface()->AddToConsole(this, message);
1708 ShutdownProxy();
1709 // Inform JavaScript that loading encountered an error and is complete.
1710 EnqueueProgressEvent("error",
1711 LENGTH_IS_NOT_COMPUTABLE,
1712 kUnknownBytes,
1713 kUnknownBytes);
1714 EnqueueProgressEvent("loadend",
1715 LENGTH_IS_NOT_COMPUTABLE,
1716 kUnknownBytes,
1717 kUnknownBytes);
1718
1719 // UMA
1720 HistogramEnumerateLoadStatus(error_info.error_code());
1721 }
1722
1723
1724 void Plugin::ReportLoadAbort() {
1725 PLUGIN_PRINTF(("Plugin::ReportLoadAbort\n"));
1726 // Set the readyState attribute to indicate we need to start over.
1727 set_nacl_ready_state(DONE);
1728 // Report an error in lastError and on the JavaScript console.
1729 nacl::string error_string("NaCl module load failed: user aborted");
1730 set_last_error_string(error_string);
1731 browser_interface()->AddToConsole(this, error_string);
1732 ShutdownProxy();
1733 // Inform JavaScript that loading was aborted and is complete.
1734 EnqueueProgressEvent("abort",
1735 LENGTH_IS_NOT_COMPUTABLE,
1736 kUnknownBytes,
1737 kUnknownBytes);
1738 EnqueueProgressEvent("loadend",
1739 LENGTH_IS_NOT_COMPUTABLE,
1740 kUnknownBytes,
1741 kUnknownBytes);
1742
1743 // UMA
1744 HistogramEnumerateLoadStatus(ERROR_LOAD_ABORTED);
1745 }
1746
1747
1748 void Plugin::EnqueueProgressEvent(const char* event_type,
1749 LengthComputable length_computable,
1750 uint64_t loaded_bytes,
1751 uint64_t total_bytes) {
1752 PLUGIN_PRINTF(("Plugin::EnqueueProgressEvent ("
1753 "event_type='%s', length_computable=%d, "
1754 "loaded=%"NACL_PRIu64", total=%"NACL_PRIu64")\n",
1755 event_type,
1756 static_cast<int>(length_computable),
1757 loaded_bytes,
1758 total_bytes));
1759
1760 progress_events_.push(new ProgressEvent(event_type,
1761 length_computable,
1762 loaded_bytes,
1763 total_bytes));
1764 // Note that using callback_factory_ in this way is not thread safe.
1765 // If/when EnqueueProgressEvent is callable from another thread, this
1766 // will need to change.
1767 pp::CompletionCallback callback =
1768 callback_factory_.NewCallback(&Plugin::DispatchProgressEvent);
1769 pp::Core* core = pp::Module::Get()->core();
1770 core->CallOnMainThread(0, callback, 0);
1771 }
1772
1773 void Plugin::ReportSelLdrLoadStatus(int status) {
1774 HistogramEnumerateSelLdrLoadStatus(static_cast<NaClErrorCode>(status));
1775 }
1776
1777 void Plugin::DispatchProgressEvent(int32_t result) {
1778 PLUGIN_PRINTF(("Plugin::DispatchProgressEvent (result=%"
1779 NACL_PRId32")\n", result));
1780 if (result < 0) {
1781 return;
1782 }
1783 if (progress_events_.empty()) {
1784 PLUGIN_PRINTF(("Plugin::DispatchProgressEvent: no pending events\n"));
1785 return;
1786 }
1787 nacl::scoped_ptr<ProgressEvent> event(progress_events_.front());
1788 progress_events_.pop();
1789 PLUGIN_PRINTF(("Plugin::DispatchProgressEvent ("
1790 "event_type='%s', length_computable=%d, "
1791 "loaded=%"NACL_PRIu64", total=%"NACL_PRIu64")\n",
1792 event->event_type(),
1793 static_cast<int>(event->length_computable()),
1794 event->loaded_bytes(),
1795 event->total_bytes()));
1796
1797 static const char* kEventClosureJS =
1798 "(function(target, type, lengthComputable, loadedBytes, totalBytes) {"
1799 " var progress_event = document.createEvent('ProgressEvent');"
1800 " progress_event.initProgressEvent(type, false, true,"
1801 " lengthComputable,"
1802 " loadedBytes,"
1803 " totalBytes);"
1804 " target.dispatchEvent(progress_event);"
1805 "})";
1806
1807 // Create a function object by evaluating the JavaScript text.
1808 // TODO(sehr, polina): We should probably cache the created function object to
1809 // avoid JavaScript reparsing.
1810 pp::VarPrivate exception;
1811 pp::VarPrivate function_object = ExecuteScript(kEventClosureJS, &exception);
1812 if (!exception.is_undefined() || !function_object.is_object()) {
1813 PLUGIN_PRINTF(("Plugin::DispatchProgressEvent:"
1814 " Function object creation failed.\n"));
1815 return;
1816 }
1817 // Get the target of the event to be dispatched.
1818 pp::Var owner_element_object = GetOwnerElementObject();
1819 if (!owner_element_object.is_object()) {
1820 PLUGIN_PRINTF(("Plugin::DispatchProgressEvent:"
1821 " Couldn't get owner element object.\n"));
1822 NACL_NOTREACHED();
1823 return;
1824 }
1825
1826 pp::Var argv[5];
1827 static const uint32_t argc = NACL_ARRAY_SIZE(argv);
1828 argv[0] = owner_element_object;
1829 argv[1] = pp::Var(event->event_type());
1830 argv[2] = pp::Var(event->length_computable() == LENGTH_IS_COMPUTABLE);
1831 argv[3] = pp::Var(static_cast<double>(event->loaded_bytes()));
1832 argv[4] = pp::Var(static_cast<double>(event->total_bytes()));
1833
1834 // Dispatch the event.
1835 const pp::Var default_method;
1836 function_object.Call(default_method, argc, argv, &exception);
1837 if (!exception.is_undefined()) {
1838 PLUGIN_PRINTF(("Plugin::DispatchProgressEvent:"
1839 " event dispatch failed.\n"));
1840 }
1841 }
1842
1843 UrlSchemeType Plugin::GetUrlScheme(const std::string& url) {
1844 CHECK(url_util_ != NULL);
1845 PP_URLComponents_Dev comps;
1846 pp::Var canonicalized =
1847 url_util_->Canonicalize(pp::Var(url), &comps);
1848
1849 if (canonicalized.is_null() ||
1850 (comps.scheme.begin == 0 && comps.scheme.len == -1)) {
1851 // |url| was an invalid URL or has no scheme.
1852 return SCHEME_OTHER;
1853 }
1854
1855 CHECK(comps.scheme.begin <
1856 static_cast<int>(canonicalized.AsString().size()));
1857 CHECK(comps.scheme.begin + comps.scheme.len <
1858 static_cast<int>(canonicalized.AsString().size()));
1859
1860 std::string scheme = canonicalized.AsString().substr(comps.scheme.begin,
1861 comps.scheme.len);
1862 if (scheme == kChromeExtensionUriScheme)
1863 return SCHEME_CHROME_EXTENSION;
1864 if (scheme == kDataUriScheme)
1865 return SCHEME_DATA;
1866 return SCHEME_OTHER;
1867 }
1868
1869 } // namespace plugin
OLDNEW
« no previous file with comments | « src/trusted/plugin/plugin.h ('k') | src/trusted/plugin/plugin.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698