#include <sys/types.h>
#include <algorithm>
-#include <deque>
#include <string>
#include <vector>
#include "native_client/src/trusted/service_runtime/nacl_error_code.h"
#include "ppapi/c/pp_errors.h"
-#include "ppapi/c/ppb_console.h"
#include "ppapi/c/ppb_var.h"
#include "ppapi/c/private/ppb_nacl_private.h"
#include "ppapi/cpp/dev/url_util_dev.h"
#include "ppapi/cpp/module.h"
-#include "ppapi/cpp/text_input_controller.h"
-#include "ppapi/native_client/src/trusted/plugin/file_utils.h"
-#include "ppapi/native_client/src/trusted/plugin/json_manifest.h"
#include "ppapi/native_client/src/trusted/plugin/nacl_entry_points.h"
#include "ppapi/native_client/src/trusted/plugin/nacl_subprocess.h"
#include "ppapi/native_client/src/trusted/plugin/plugin_error.h"
namespace {
-const char* const kTypeAttribute = "type";
-// The "src" attribute of the <embed> tag. The value is expected to be either
-// a URL or URI pointing to the manifest file (which is expected to contain
-// JSON matching ISAs with .nexe URLs).
-const char* const kSrcManifestAttribute = "src";
-// The "nacl" attribute of the <embed> tag. We use the value of this attribute
-// to find the manifest file when NaCl is registered as a plug-in for another
-// MIME type because the "src" attribute is used to supply us with the resource
-// of that MIME type that we're supposed to display.
-const char* const kNaClManifestAttribute = "nacl";
// The pseudo-architecture used to indicate portable native client.
const char* const kPortableArch = "portable";
// This is a pretty arbitrary limit on the byte size of the NaCl manfest file.
// for the null termination character.
const size_t kNaClManifestMaxFileBytes = 1024 * 1024;
-// Define an argument name to enable 'dev' interfaces. To make sure it doesn't
-// collide with any user-defined HTML attribute, make the first character '@'.
-const char* const kDevAttribute = "@dev";
-
// Up to 20 seconds
const int64_t kTimeSmallMin = 1; // in ms
const int64_t kTimeSmallMax = 20000; // in ms
const uint32_t kTimeSmallBuckets = 100;
-// Up to 3 minutes, 20 seconds
-const int64_t kTimeMediumMin = 10; // in ms
-const int64_t kTimeMediumMax = 200000; // in ms
-const uint32_t kTimeMediumBuckets = 100;
-
-// Up to 33 minutes.
-const int64_t kTimeLargeMin = 100; // in ms
-const int64_t kTimeLargeMax = 2000000; // in ms
-const uint32_t kTimeLargeBuckets = 100;
-
const int64_t kSizeKBMin = 1;
const int64_t kSizeKBMax = 512*1024; // very large .nexe
const uint32_t kSizeKBBuckets = 100;
-const PPB_NaCl_Private* GetNaClInterface() {
- pp::Module *module = pp::Module::Get();
- CHECK(module);
- return static_cast<const PPB_NaCl_Private*>(
- module->GetBrowserInterface(PPB_NACL_PRIVATE_INTERFACE));
-}
-
} // namespace
-bool Plugin::EarlyInit(int argc, const char* argn[], const char* argv[]) {
- PLUGIN_PRINTF(("Plugin::EarlyInit (instance=%p)\n",
- static_cast<void*>(this)));
-
-#ifdef NACL_OSX
- // TODO(kochi): For crbug.com/102808, this is a stopgap solution for Lion
- // until we expose IME API to .nexe. This disables any IME interference
- // against key inputs, so you cannot use off-the-spot IME input for NaCl apps.
- // This makes discrepancy among platforms and therefore we should remove
- // this hack when IME API is made available.
- // The default for non-Mac platforms is still off-the-spot IME mode.
- pp::TextInputController(this).SetTextInputType(PP_TEXTINPUT_TYPE_NONE);
-#endif
-
- for (int i = 0; i < argc; ++i) {
- std::string name(argn[i]);
- std::string value(argv[i]);
- args_[name] = value;
- }
-
- // Set up the factory used to produce DescWrappers.
- wrapper_factory_ = new nacl::DescWrapperFactory();
- if (NULL == wrapper_factory_) {
- return false;
- }
- PLUGIN_PRINTF(("Plugin::Init (wrapper_factory=%p)\n",
- static_cast<void*>(wrapper_factory_)));
-
- PLUGIN_PRINTF(("Plugin::Init (return 1)\n"));
- // Return success.
- return true;
-}
-
void Plugin::ShutDownSubprocesses() {
PLUGIN_PRINTF(("Plugin::ShutDownSubprocesses (this=%p)\n",
static_cast<void*>(this)));
kTimeSmallBuckets);
}
-void Plugin::HistogramTimeMedium(const std::string& name,
- int64_t ms) {
- if (ms < 0) return;
- uma_interface_.HistogramCustomTimes(name,
- ms,
- kTimeMediumMin, kTimeMediumMax,
- kTimeMediumBuckets);
-}
-
-void Plugin::HistogramTimeLarge(const std::string& name,
- int64_t ms) {
- if (ms < 0) return;
- uma_interface_.HistogramCustomTimes(name,
- ms,
- kTimeLargeMin, kTimeLargeMax,
- kTimeLargeBuckets);
-}
-
void Plugin::HistogramSizeKB(const std::string& name,
int32_t sample) {
if (sample < 0) return;
uma_interface_.HistogramEnumeration(name, sample, maximum);
}
-void Plugin::HistogramEnumerateOsArch(const std::string& sandbox_isa) {
- enum NaClOSArch {
- kNaClLinux32 = 0,
- kNaClLinux64,
- kNaClLinuxArm,
- kNaClMac32,
- kNaClMac64,
- kNaClMacArm,
- kNaClWin32,
- kNaClWin64,
- kNaClWinArm,
- kNaClLinuxMips,
- kNaClOSArchMax
- };
-
- NaClOSArch os_arch = kNaClOSArchMax;
-#if NACL_LINUX
- os_arch = kNaClLinux32;
-#elif NACL_OSX
- os_arch = kNaClMac32;
-#elif NACL_WINDOWS
- os_arch = kNaClWin32;
-#endif
-
- if (sandbox_isa == "x86-64")
- os_arch = static_cast<NaClOSArch>(os_arch + 1);
- if (sandbox_isa == "arm")
- os_arch = static_cast<NaClOSArch>(os_arch + 2);
- if (sandbox_isa == "mips32")
- os_arch = kNaClLinuxMips;
-
- HistogramEnumerate("NaCl.Client.OSArch", os_arch, kNaClOSArchMax, -1);
-}
-
-void Plugin::HistogramEnumerateLoadStatus(PP_NaClError error_code) {
- HistogramEnumerate("NaCl.LoadStatus.Plugin", error_code, PP_NACL_ERROR_MAX,
- PP_NACL_ERROR_UNKNOWN);
-
- // Gather data to see if being installed changes load outcomes.
- const char* name = nacl_interface_->GetIsInstalled(pp_instance()) ?
- "NaCl.LoadStatus.Plugin.InstalledApp" :
- "NaCl.LoadStatus.Plugin.NotInstalledApp";
- HistogramEnumerate(name, error_code, PP_NACL_ERROR_MAX,
- PP_NACL_ERROR_UNKNOWN);
-}
-
void Plugin::HistogramEnumerateSelLdrLoadStatus(NaClErrorCode error_code) {
HistogramEnumerate("NaCl.LoadStatus.SelLdr", error_code,
NACL_ERROR_CODE_MAX, LOAD_STATUS_UNKNOWN);
LOAD_STATUS_UNKNOWN);
}
-void Plugin::HistogramEnumerateManifestIsDataURI(bool is_data_uri) {
- HistogramEnumerate("NaCl.Manifest.IsDataURI", is_data_uri, 2, -1);
-}
-
-void Plugin::HistogramHTTPStatusCode(const std::string& name,
- int status) {
+void Plugin::HistogramHTTPStatusCode(const std::string& name, int status) {
// Log the status codes in rough buckets - 1XX, 2XX, etc.
int sample = status / 100;
// HTTP status codes only go up to 5XX, using "6" to indicate an internal
bool Plugin::LoadNaClModuleFromBackgroundThread(
nacl::DescWrapper* wrapper,
NaClSubprocess* subprocess,
- const Manifest* manifest,
+ int32_t manifest_id,
const SelLdrStartParams& params) {
CHECK(!pp::Module::Get()->core()->IsMainThread());
ServiceRuntime* service_runtime =
- new ServiceRuntime(this, manifest, false, uses_nonsfi_mode_,
+ new ServiceRuntime(this, manifest_id, false, uses_nonsfi_mode_,
pp::BlockUntilComplete(), pp::BlockUntilComplete());
subprocess->set_service_runtime(service_runtime);
PLUGIN_PRINTF(("Plugin::LoadNaClModuleFromBackgroundThread "
// associated listener threads do not go unjoined because if they
// outlive the Plugin object, they will not be memory safe.
ShutDownSubprocesses();
- SelLdrStartParams params(manifest_base_url(),
+ pp::Var manifest_base_url =
+ pp::Var(pp::PASS_REF, nacl_interface_->GetManifestBaseURL(pp_instance()));
+ std::string manifest_base_url_str = manifest_base_url.AsString();
+ bool enable_dev_interfaces =
+ nacl_interface_->DevInterfacesEnabled(pp_instance());
+ SelLdrStartParams params(manifest_base_url_str,
true /* uses_irt */,
true /* uses_ppapi */,
uses_nonsfi_mode,
- enable_dev_interfaces_,
+ enable_dev_interfaces,
enable_dyncode_syscalls,
enable_exception_handling,
enable_crash_throttling);
ErrorInfo error_info;
ServiceRuntime* service_runtime =
- new ServiceRuntime(this, manifest_.get(), true, uses_nonsfi_mode,
+ new ServiceRuntime(this, manifest_id_, true, uses_nonsfi_mode,
init_done_cb, crash_cb);
main_subprocess_.set_service_runtime(service_runtime);
PLUGIN_PRINTF(("Plugin::LoadNaClModule (service_runtime=%p)\n",
}
}
-bool Plugin::LoadNaClModuleContinuationIntern(ErrorInfo* error_info) {
+bool Plugin::LoadNaClModuleContinuationIntern() {
+ ErrorInfo error_info;
if (!uses_nonsfi_mode_) {
if (!main_subprocess_.StartSrpcServices()) {
// The NaCl process probably crashed. On Linux, a crash causes this
// to make it less confusing for developers.
NaClLog(LOG_ERROR, "LoadNaClModuleContinuationIntern: "
"StartSrpcServices failed\n");
- error_info->SetReport(PP_NACL_ERROR_START_PROXY_MODULE,
- "could not initialize module.");
+ error_info.SetReport(PP_NACL_ERROR_START_PROXY_MODULE,
+ "could not initialize module.");
+ ReportLoadError(error_info);
return false;
}
}
- PP_ExternalPluginResult ipc_result =
- nacl_interface_->StartPpapiProxy(pp_instance());
- if (ipc_result == PP_EXTERNAL_PLUGIN_OK) {
- // Log the amound of time that has passed between the trusted plugin being
- // initialized and the untrusted plugin being initialized. This is
- // (roughly) the cost of using NaCl, in terms of startup time.
- HistogramStartupTimeMedium(
- "NaCl.Perf.StartupTime.NaClOverhead",
- static_cast<float>(NaClGetTimeOfDayMicroseconds() - init_time_)
- / NACL_MICROS_PER_MILLI);
- } else if (ipc_result == PP_EXTERNAL_PLUGIN_ERROR_MODULE) {
- NaClLog(LOG_ERROR, "LoadNaClModuleContinuationIntern: "
- "Got PP_EXTERNAL_PLUGIN_ERROR_MODULE\n");
- error_info->SetReport(PP_NACL_ERROR_START_PROXY_MODULE,
- "could not initialize module.");
- return false;
- } else if (ipc_result == PP_EXTERNAL_PLUGIN_ERROR_INSTANCE) {
- error_info->SetReport(PP_NACL_ERROR_START_PROXY_INSTANCE,
- "could not create instance.");
- return false;
+
+ bool result = PP_ToBool(nacl_interface_->StartPpapiProxy(pp_instance()));
+ if (result) {
+ PLUGIN_PRINTF(("Plugin::LoadNaClModule (%s)\n",
+ main_subprocess_.detailed_description().c_str()));
}
- PLUGIN_PRINTF(("Plugin::LoadNaClModule (%s)\n",
- main_subprocess_.detailed_description().c_str()));
- return true;
+ return result;
}
NaClSubprocess* Plugin::LoadHelperNaClModule(const nacl::string& helper_url,
nacl::DescWrapper* wrapper,
- const Manifest* manifest,
+ int32_t manifest_id,
ErrorInfo* error_info) {
nacl::scoped_ptr<NaClSubprocess> nacl_subprocess(
new NaClSubprocess("helper module", NULL, NULL));
// done to save on address space and swap space.
// TODO(jvoung): See if we still need the uses_ppapi variable, now that
// LaunchSelLdr always happens on the main thread.
+ bool enable_dev_interfaces =
+ nacl_interface_->DevInterfacesEnabled(pp_instance());
SelLdrStartParams params(helper_url,
false /* uses_irt */,
false /* uses_ppapi */,
false /* uses_nonsfi_mode */,
- enable_dev_interfaces_,
+ enable_dev_interfaces,
false /* enable_dyncode_syscalls */,
false /* enable_exception_handling */,
true /* enable_crash_throttling */);
if (!LoadNaClModuleFromBackgroundThread(wrapper, nacl_subprocess.get(),
- manifest, params)) {
+ manifest_id, params)) {
return NULL;
}
// We need not wait for the init_done callback. We can block
return nacl_subprocess.release();
}
-std::string Plugin::LookupArgument(const std::string& key) const {
- std::map<std::string, std::string>::const_iterator it = args_.find(key);
- if (it != args_.end())
- return it->second;
- return std::string();
-}
-
-const char* const Plugin::kNaClMIMEType = "application/x-nacl";
-const char* const Plugin::kPnaclMIMEType = "application/x-pnacl";
-
-bool Plugin::NexeIsContentHandler() const {
- // Tests if the MIME type is not a NaCl MIME type.
- // If the MIME type is foreign, then this NEXE is being used as a content
- // type handler rather than directly by an HTML document.
- return
- !mime_type().empty() &&
- mime_type() != kNaClMIMEType &&
- mime_type() != kPnaclMIMEType;
-}
-
-
-Plugin* Plugin::New(PP_Instance pp_instance) {
- PLUGIN_PRINTF(("Plugin::New (pp_instance=%" NACL_PRId32 ")\n", pp_instance));
- Plugin* plugin = new Plugin(pp_instance);
- PLUGIN_PRINTF(("Plugin::New (plugin=%p)\n", static_cast<void*>(plugin)));
- return plugin;
-}
-
-
// All failures of this function will show up as "Missing Plugin-in", so
// there is no need to log to JS console that there was an initialization
// failure. Note that module loading functions will log their own errors.
bool Plugin::Init(uint32_t argc, const char* argn[], const char* argv[]) {
PLUGIN_PRINTF(("Plugin::Init (argc=%" NACL_PRIu32 ")\n", argc));
- HistogramEnumerateOsArch(nacl_interface_->GetSandboxArch());
- init_time_ = NaClGetTimeOfDayMicroseconds();
- url_util_ = pp::URLUtil_Dev::Get();
- if (url_util_ == NULL)
- return false;
-
- PLUGIN_PRINTF(("Plugin::Init (url_util_=%p)\n",
- static_cast<const void*>(url_util_)));
-
- bool status = EarlyInit(static_cast<int>(argc), argn, argv);
- if (status) {
- // Look for the developer attribute; if it's present, enable 'dev'
- // interfaces.
- enable_dev_interfaces_ = args_.find(kDevAttribute) != args_.end();
-
- mime_type_ = LookupArgument(kTypeAttribute);
- std::transform(mime_type_.begin(), mime_type_.end(), mime_type_.begin(),
- tolower);
-
- std::string manifest_url;
- if (NexeIsContentHandler()) {
- // For content handlers 'src' will be the URL for the content
- // and 'nacl' will be the URL for the manifest.
- manifest_url = LookupArgument(kNaClManifestAttribute);
- // For content handlers the NEXE runs in the security context of the
- // content it is rendering and the NEXE itself appears to be a
- // cross-origin resource stored in a Chrome extension.
- } else {
- manifest_url = LookupArgument(kSrcManifestAttribute);
- }
- // Use the document URL as the base for resolving relative URLs to find the
- // manifest. This takes into account the setting of <base> tags that
- // precede the embed/object.
- CHECK(url_util_ != NULL);
- pp::Var base_var = url_util_->GetDocumentURL(this);
- if (!base_var.is_string()) {
- PLUGIN_PRINTF(("Plugin::Init (unable to find document url)\n"));
- return false;
- }
- set_plugin_base_url(base_var.AsString());
- if (manifest_url.empty()) {
- // TODO(sehr,polina): this should be a hard error when scripting
- // the src property is no longer allowed.
- PLUGIN_PRINTF(("Plugin::Init:"
- " WARNING: no 'src' property, so no manifest loaded.\n"));
- if (args_.find(kNaClManifestAttribute) != args_.end()) {
- PLUGIN_PRINTF(("Plugin::Init:"
- " WARNING: 'nacl' property is incorrect. Use 'src'.\n"));
- }
- } else {
- // Issue a GET for the manifest_url. The manifest file will be parsed to
- // determine the nexe URL.
- // Sets src property to full manifest URL.
- RequestNaClManifest(manifest_url.c_str());
- }
- }
-
- PLUGIN_PRINTF(("Plugin::Init (status=%d)\n", status));
- return status;
+ nacl_interface_->InitializePlugin(pp_instance(), argc, argn, argv);
+ wrapper_factory_ = new nacl::DescWrapperFactory();
+ pp::Var manifest_url(pp::PASS_REF, nacl_interface_->GetManifestURLArgument(
+ pp_instance()));
+ if (manifest_url.is_string() && !manifest_url.AsString().empty())
+ RequestNaClManifest(manifest_url.AsString());
+ return true;
}
Plugin::Plugin(PP_Instance pp_instance)
main_subprocess_("main subprocess", NULL, NULL),
uses_nonsfi_mode_(false),
wrapper_factory_(NULL),
- enable_dev_interfaces_(false),
- init_time_(0),
- ready_time_(0),
- nexe_size_(0),
time_of_last_progress_event_(0),
- exit_status_(-1),
+ nexe_open_time_(-1),
+ manifest_id_(-1),
nacl_interface_(NULL),
uma_interface_(this) {
PLUGIN_PRINTF(("Plugin::Plugin (this=%p, pp_instance=%"
// Notify PPB_NaCl_Private that the instance is created before altering any
// state that it tracks.
nacl_interface_->InstanceCreated(pp_instance);
- set_last_error_string("");
// We call set_exit_status() here to ensure that the 'exitStatus' property is
// set. This can only be called when nacl_interface_ is not NULL.
set_exit_status(-1);
// Destroy the coordinator while the rest of the data is still there
pnacl_coordinator_.reset(NULL);
- if (!nacl_interface_->GetNexeErrorReported(pp_instance())) {
- HistogramTimeLarge(
- "NaCl.ModuleUptime.Normal",
- (shutdown_start - ready_time_) / NACL_MICROS_PER_MILLI);
- }
-
for (std::map<nacl::string, NaClFileInfoAutoCloser*>::iterator it =
url_file_info_map_.begin();
it != url_file_info_map_.end();
return true;
}
-void Plugin::HistogramStartupTimeSmall(const std::string& name, float dt) {
- if (nexe_size_ > 0) {
- float size_in_MB = static_cast<float>(nexe_size_) / (1024.f * 1024.f);
- HistogramTimeSmall(name, static_cast<int64_t>(dt));
- HistogramTimeSmall(name + "PerMB", static_cast<int64_t>(dt / size_in_MB));
- }
-}
-
-void Plugin::HistogramStartupTimeMedium(const std::string& name, float dt) {
- if (nexe_size_ > 0) {
- float size_in_MB = static_cast<float>(nexe_size_) / (1024.f * 1024.f);
- HistogramTimeMedium(name, static_cast<int64_t>(dt));
- HistogramTimeMedium(name + "PerMB", static_cast<int64_t>(dt / size_in_MB));
- }
-}
-
void Plugin::NexeFileDidOpen(int32_t pp_error) {
- PLUGIN_PRINTF(("Plugin::NexeFileDidOpen (pp_error=%" NACL_PRId32 ")\n",
- pp_error));
NaClFileInfo tmp_info(nexe_downloader_.GetFileInfo());
NaClFileInfoAutoCloser info(&tmp_info);
- PLUGIN_PRINTF(("Plugin::NexeFileDidOpen (file_desc=%" NACL_PRId32 ")\n",
- info.get_desc()));
- HistogramHTTPStatusCode(
- nacl_interface_->GetIsInstalled(pp_instance()) ?
- "NaCl.HttpStatusCodeClass.Nexe.InstalledApp" :
- "NaCl.HttpStatusCodeClass.Nexe.NotInstalledApp",
- nexe_downloader_.status_code());
- ErrorInfo error_info;
- if (pp_error != PP_OK || info.get_desc() == NACL_NO_FILE_DESC) {
- if (pp_error == PP_ERROR_ABORTED) {
- ReportLoadAbort();
- } else if (pp_error == PP_ERROR_NOACCESS) {
- error_info.SetReport(PP_NACL_ERROR_NEXE_NOACCESS_URL,
- "access to nexe url was denied.");
- ReportLoadError(error_info);
- } else {
- error_info.SetReport(PP_NACL_ERROR_NEXE_LOAD_URL,
- "could not load nexe url.");
- ReportLoadError(error_info);
- }
- return;
- }
- int32_t file_desc_ok_to_close = DUP(info.get_desc());
- if (file_desc_ok_to_close == NACL_NO_FILE_DESC) {
- error_info.SetReport(PP_NACL_ERROR_NEXE_FH_DUP,
- "could not duplicate loaded file handle.");
- ReportLoadError(error_info);
- return;
+
+ int64_t nexe_bytes_read = -1;
+ if (pp_error == PP_OK && info.get_desc() != NACL_NO_FILE_DESC) {
+ struct stat stat_buf;
+ if (0 == fstat(info.get_desc(), &stat_buf))
+ nexe_bytes_read = stat_buf.st_size;
}
- struct stat stat_buf;
- if (0 != fstat(file_desc_ok_to_close, &stat_buf)) {
- CLOSE(file_desc_ok_to_close);
- error_info.SetReport(PP_NACL_ERROR_NEXE_STAT, "could not stat nexe file.");
- ReportLoadError(error_info);
+
+ int64_t now = NaClGetTimeOfDayMicroseconds();
+ int64_t download_time;
+ if (now < nexe_open_time_)
+ download_time = 0;
+ else
+ download_time = now - nexe_open_time_;
+
+ nacl_interface_->NexeFileDidOpen(
+ pp_instance(),
+ pp_error,
+ info.get_desc(),
+ nexe_downloader_.status_code(),
+ nexe_bytes_read,
+ nexe_downloader_.url().c_str(),
+ download_time / 1000);
+
+ if (nexe_bytes_read == -1)
return;
- }
- size_t nexe_bytes_read = static_cast<size_t>(stat_buf.st_size);
-
- nexe_size_ = nexe_bytes_read;
- HistogramSizeKB("NaCl.Perf.Size.Nexe",
- static_cast<int32_t>(nexe_size_ / 1024));
- HistogramStartupTimeMedium(
- "NaCl.Perf.StartupTime.NexeDownload",
- static_cast<float>(nexe_downloader_.TimeSinceOpenMilliseconds()));
-
- // Inform JavaScript that we successfully downloaded the nacl module.
- EnqueueProgressEvent(PP_NACL_EVENT_PROGRESS,
- nexe_downloader_.url(),
- LENGTH_IS_COMPUTABLE,
- nexe_bytes_read,
- nexe_bytes_read);
-
- load_start_ = NaClGetTimeOfDayMicroseconds();
+
nacl::scoped_ptr<nacl::DescWrapper>
- wrapper(wrapper_factory()->MakeFileDesc(file_desc_ok_to_close, O_RDONLY));
+ wrapper(wrapper_factory()->MakeFileDesc(info.Release().desc, O_RDONLY));
NaClLog(4, "NexeFileDidOpen: invoking LoadNaClModule\n");
LoadNaClModule(
wrapper.release(),
}
void Plugin::NexeFileDidOpenContinuation(int32_t pp_error) {
- ErrorInfo error_info;
bool was_successful;
UNREFERENCED_PARAMETER(pp_error);
NaClLog(4, "Entered NexeFileDidOpenContinuation\n");
NaClLog(4, "NexeFileDidOpenContinuation: invoking"
" LoadNaClModuleContinuationIntern\n");
- was_successful = LoadNaClModuleContinuationIntern(&error_info);
+ was_successful = LoadNaClModuleContinuationIntern();
if (was_successful) {
NaClLog(4, "NexeFileDidOpenContinuation: success;"
" setting histograms\n");
- ready_time_ = NaClGetTimeOfDayMicroseconds();
- HistogramStartupTimeSmall(
- "NaCl.Perf.StartupTime.LoadModule",
- static_cast<float>(ready_time_ - load_start_) / NACL_MICROS_PER_MILLI);
- HistogramStartupTimeMedium(
- "NaCl.Perf.StartupTime.Total",
- static_cast<float>(ready_time_ - init_time_) / NACL_MICROS_PER_MILLI);
-
- ReportLoadSuccess(LENGTH_IS_COMPUTABLE, nexe_size_, nexe_size_);
+ int64_t nexe_size = nacl_interface_->GetNexeSize(pp_instance());
+ ReportLoadSuccess(nexe_size, nexe_size);
} else {
NaClLog(4, "NexeFileDidOpenContinuation: failed.");
- ReportLoadError(error_info);
}
NaClLog(4, "Leaving NexeFileDidOpenContinuation\n");
}
-static void LogLineToConsole(Plugin* plugin, const nacl::string& one_line) {
- PLUGIN_PRINTF(("LogLineToConsole: %s\n",
- one_line.c_str()));
- plugin->nacl_interface()->LogToConsole(plugin->pp_instance(),
- one_line.c_str());
-}
-
-void Plugin::CopyCrashLogToJsConsole() {
- nacl::string fatal_msg(main_service_runtime()->GetCrashLogOutput());
- size_t ix_start = 0;
- size_t ix_end;
-
- PLUGIN_PRINTF(("Plugin::CopyCrashLogToJsConsole: got %" NACL_PRIuS " bytes\n",
- fatal_msg.size()));
- while (nacl::string::npos != (ix_end = fatal_msg.find('\n', ix_start))) {
- LogLineToConsole(this, fatal_msg.substr(ix_start, ix_end - ix_start));
- ix_start = ix_end + 1;
- }
- if (ix_start != fatal_msg.size()) {
- LogLineToConsole(this, fatal_msg.substr(ix_start));
- }
-}
-
void Plugin::NexeDidCrash(int32_t pp_error) {
PLUGIN_PRINTF(("Plugin::NexeDidCrash (pp_error=%" NACL_PRId32 ")\n",
pp_error));
PLUGIN_PRINTF(("Plugin::NexeDidCrash: CallOnMainThread callback with"
" non-PP_OK arg -- SHOULD NOT HAPPEN\n"));
}
- PLUGIN_PRINTF(("Plugin::NexeDidCrash: crash event!\n"));
- if (-1 != exit_status()) {
- // The NaCl module voluntarily exited. However, this is still a
- // crash from the point of view of Pepper, since PPAPI plugins are
- // event handlers and should never exit.
- PLUGIN_PRINTF((("Plugin::NexeDidCrash: nexe exited with status %d"
- " so this is a \"controlled crash\".\n"),
- exit_status()));
- }
- // If the crash occurs during load, we just want to report an error
- // that fits into our load progress event grammar. If the crash
- // occurs after loaded/loadend, then we use ReportDeadNexe to send a
- // "crash" event.
- if (nacl_interface_->GetNexeErrorReported(pp_instance())) {
- PLUGIN_PRINTF(("Plugin::NexeDidCrash: error already reported;"
- " suppressing\n"));
- } else {
- if (nacl_interface_->GetNaClReadyState(pp_instance()) ==
- PP_NACL_READY_STATE_DONE) {
- ReportDeadNexe();
- } else {
- ErrorInfo error_info;
- // The error is not quite right. In particular, the crash
- // reported by this path could be due to NaCl application
- // crashes that occur after the PPAPI proxy has started.
- error_info.SetReport(PP_NACL_ERROR_START_PROXY_CRASH,
- "Nexe crashed during startup");
- ReportLoadError(error_info);
- }
- }
- // In all cases, try to grab the crash log. The first error
- // reported may have come from the start_module RPC reply indicating
- // a validation error or something similar, which wouldn't grab the
- // crash log. In the event that this is called twice, the second
- // invocation will just be a no-op, since all the crash log will
- // have been received and we'll just get an EOF indication.
- CopyCrashLogToJsConsole();
+ std::string crash_log = main_service_runtime()->GetCrashLogOutput();
+ nacl_interface_->NexeDidCrash(pp_instance(), crash_log.c_str());
}
void Plugin::BitcodeDidTranslate(int32_t pp_error) {
}
void Plugin::BitcodeDidTranslateContinuation(int32_t pp_error) {
- ErrorInfo error_info;
- bool was_successful = LoadNaClModuleContinuationIntern(&error_info);
+ bool was_successful = LoadNaClModuleContinuationIntern();
NaClLog(4, "Entered BitcodeDidTranslateContinuation\n");
UNREFERENCED_PARAMETER(pp_error);
int64_t loaded;
int64_t total;
pnacl_coordinator_->GetCurrentProgress(&loaded, &total);
- ReportLoadSuccess(LENGTH_IS_COMPUTABLE, loaded, total);
- } else {
- ReportLoadError(error_info);
- }
-}
-
-void Plugin::ReportDeadNexe() {
- PLUGIN_PRINTF(("Plugin::ReportDeadNexe\n"));
-
- PP_NaClReadyState ready_state =
- nacl_interface_->GetNaClReadyState(pp_instance());
- if (ready_state == PP_NACL_READY_STATE_DONE && // After loadEnd
- !nacl_interface_->GetNexeErrorReported(pp_instance())) {
- int64_t crash_time = NaClGetTimeOfDayMicroseconds();
- // Crashes will be more likely near startup, so use a medium histogram
- // instead of a large one.
- HistogramTimeMedium(
- "NaCl.ModuleUptime.Crash",
- (crash_time - ready_time_) / NACL_MICROS_PER_MILLI);
-
- nacl::string message = nacl::string("NaCl module crashed");
- set_last_error_string(message);
- nacl_interface()->LogToConsole(pp_instance(), message.c_str());
-
- EnqueueProgressEvent(PP_NACL_EVENT_CRASH);
- nacl_interface_->SetNexeErrorReported(pp_instance(), PP_TRUE);
+ ReportLoadSuccess(loaded, total);
}
- // else ReportLoadError() and ReportAbortError() will be used by loading code
- // to provide error handling.
-}
-
-void Plugin::NaClManifestBufferReady(int32_t pp_error) {
- PLUGIN_PRINTF(("Plugin::NaClManifestBufferReady (pp_error=%"
- NACL_PRId32 ")\n", pp_error));
- ErrorInfo error_info;
- if (pp_error != PP_OK) {
- if (pp_error == PP_ERROR_ABORTED) {
- ReportLoadAbort();
- } else {
- error_info.SetReport(PP_NACL_ERROR_MANIFEST_LOAD_URL,
- "could not load manifest url.");
- ReportLoadError(error_info);
- }
- return;
- }
-
- const std::deque<char>& buffer = nexe_downloader_.buffer();
- size_t buffer_size = buffer.size();
- if (buffer_size > kNaClManifestMaxFileBytes) {
- error_info.SetReport(PP_NACL_ERROR_MANIFEST_TOO_LARGE,
- "manifest file too large.");
- ReportLoadError(error_info);
- return;
- }
- nacl::scoped_array<char> json_buffer(new char[buffer_size + 1]);
- if (json_buffer == NULL) {
- error_info.SetReport(PP_NACL_ERROR_MANIFEST_MEMORY_ALLOC,
- "could not allocate manifest memory.");
- ReportLoadError(error_info);
- return;
- }
- std::copy(buffer.begin(), buffer.begin() + buffer_size, &json_buffer[0]);
- json_buffer[buffer_size] = '\0';
-
- ProcessNaClManifest(json_buffer.get());
}
void Plugin::NaClManifestFileDidOpen(int32_t pp_error) {
PLUGIN_PRINTF(("Plugin::NaClManifestFileDidOpen (pp_error=%"
NACL_PRId32 ")\n", pp_error));
- HistogramTimeSmall("NaCl.Perf.StartupTime.ManifestDownload",
- nexe_downloader_.TimeSinceOpenMilliseconds());
- HistogramHTTPStatusCode(
- nacl_interface_->GetIsInstalled(pp_instance()) ?
- "NaCl.HttpStatusCodeClass.Manifest.InstalledApp" :
- "NaCl.HttpStatusCodeClass.Manifest.NotInstalledApp",
- nexe_downloader_.status_code());
- ErrorInfo error_info;
- NaClFileInfo tmp_info(nexe_downloader_.GetFileInfo());
- NaClFileInfoAutoCloser info(&tmp_info);
- PLUGIN_PRINTF(("Plugin::NaClManifestFileDidOpen (file_desc=%"
- NACL_PRId32 ")\n", info.get_desc()));
- if (pp_error != PP_OK || info.get_desc() == NACL_NO_FILE_DESC) {
- if (pp_error == PP_ERROR_ABORTED) {
- ReportLoadAbort();
- } else if (pp_error == PP_ERROR_NOACCESS) {
- error_info.SetReport(PP_NACL_ERROR_MANIFEST_NOACCESS_URL,
- "access to manifest url was denied.");
- ReportLoadError(error_info);
- } else {
- error_info.SetReport(PP_NACL_ERROR_MANIFEST_LOAD_URL,
- "could not load manifest url.");
- ReportLoadError(error_info);
- }
- return;
- }
- // SlurpFile closes the file descriptor after reading (or on error).
- // Duplicate our file descriptor since it will be handled by the browser.
- int dup_file_desc = DUP(info.get_desc());
- nacl::string json_buffer;
- file_utils::StatusCode status = file_utils::SlurpFile(
- dup_file_desc, json_buffer, kNaClManifestMaxFileBytes);
-
- if (status != file_utils::PLUGIN_FILE_SUCCESS) {
- switch (status) {
- case file_utils::PLUGIN_FILE_SUCCESS:
- CHECK(0);
- break;
- case file_utils::PLUGIN_FILE_ERROR_MEM_ALLOC:
- error_info.SetReport(PP_NACL_ERROR_MANIFEST_MEMORY_ALLOC,
- "could not allocate manifest memory.");
- break;
- case file_utils::PLUGIN_FILE_ERROR_OPEN:
- error_info.SetReport(PP_NACL_ERROR_MANIFEST_OPEN,
- "could not open manifest file.");
- break;
- case file_utils::PLUGIN_FILE_ERROR_FILE_TOO_LARGE:
- error_info.SetReport(PP_NACL_ERROR_MANIFEST_TOO_LARGE,
- "manifest file too large.");
- break;
- case file_utils::PLUGIN_FILE_ERROR_STAT:
- error_info.SetReport(PP_NACL_ERROR_MANIFEST_STAT,
- "could not stat manifest file.");
- break;
- case file_utils::PLUGIN_FILE_ERROR_READ:
- error_info.SetReport(PP_NACL_ERROR_MANIFEST_READ,
- "could not read manifest file.");
- break;
- }
- ReportLoadError(error_info);
- return;
- }
+ if (pp_error == PP_OK) {
+ // Take local ownership of manifest_data_var_
+ pp::Var manifest_data = pp::Var(pp::PASS_REF, manifest_data_var_);
+ manifest_data_var_ = PP_MakeUndefined();
- ProcessNaClManifest(json_buffer);
+ std::string json_buffer = manifest_data.AsString();
+ ProcessNaClManifest(json_buffer);
+ }
}
void Plugin::ProcessNaClManifest(const nacl::string& manifest_json) {
HistogramSizeKB("NaCl.Perf.Size.Manifest",
static_cast<int32_t>(manifest_json.length() / 1024));
- ErrorInfo error_info;
- if (!SetManifestObject(manifest_json, &error_info)) {
- ReportLoadError(error_info);
+ if (!SetManifestObject(manifest_json))
return;
- }
- nacl::string program_url;
- PnaclOptions pnacl_options;
- bool uses_nonsfi_mode;
- if (manifest_->GetProgramURL(
- &program_url, &pnacl_options, &uses_nonsfi_mode, &error_info)) {
- pp::Var program_url_var(program_url);
- nacl_interface_->SetIsInstalled(
- pp_instance(),
- PP_FromBool(
- nacl_interface_->GetUrlScheme(program_url_var.pp_var()) ==
- PP_SCHEME_CHROME_EXTENSION));
- uses_nonsfi_mode_ = uses_nonsfi_mode;
- nacl_interface_->SetNaClReadyState(pp_instance(),
- PP_NACL_READY_STATE_LOADING);
- // Inform JavaScript that we found a nexe URL to load.
- EnqueueProgressEvent(PP_NACL_EVENT_PROGRESS);
- if (pnacl_options.translate()) {
+ PP_Var pp_program_url;
+ PP_PNaClOptions pnacl_options = {PP_FALSE, PP_FALSE, 2};
+ PP_Bool uses_nonsfi_mode;
+ if (nacl_interface_->GetManifestProgramURL(pp_instance(),
+ manifest_id_, &pp_program_url, &pnacl_options, &uses_nonsfi_mode)) {
+ std::string program_url = pp::Var(pp::PASS_REF, pp_program_url).AsString();
+ // TODO(teravest): Make ProcessNaClManifest take responsibility for more of
+ // this function.
+ nacl_interface_->ProcessNaClManifest(pp_instance(), program_url.c_str());
+ uses_nonsfi_mode_ = PP_ToBool(uses_nonsfi_mode);
+ if (pnacl_options.translate) {
pp::CompletionCallback translate_callback =
callback_factory_.NewCallback(&Plugin::BitcodeDidTranslate);
- // Will always call the callback on success or failure.
pnacl_coordinator_.reset(
PnaclCoordinator::BitcodeToNative(this,
program_url,
translate_callback));
return;
} else {
+ nexe_open_time_ = NaClGetTimeOfDayMicroseconds();
// Try the fast path first. This will only block if the file is installed.
if (OpenURLFast(program_url, &nexe_downloader_)) {
NexeFileDidOpen(PP_OK);
return;
}
}
- // Failed to select the program and/or the translator.
- ReportLoadError(error_info);
}
void Plugin::RequestNaClManifest(const nacl::string& url) {
PLUGIN_PRINTF(("Plugin::RequestNaClManifest (url='%s')\n", url.c_str()));
- PLUGIN_PRINTF(("Plugin::RequestNaClManifest (plugin base url='%s')\n",
- plugin_base_url().c_str()));
- // The full URL of the manifest file is relative to the base url.
- CHECK(url_util_ != NULL);
- pp::Var nmf_resolved_url =
- url_util_->ResolveRelativeToURL(plugin_base_url(), pp::Var(url));
- if (!nmf_resolved_url.is_string()) {
- ErrorInfo error_info;
- error_info.SetReport(
- PP_NACL_ERROR_MANIFEST_RESOLVE_URL,
- nacl::string("could not resolve URL \"") + url.c_str() +
- "\" relative to \"" + plugin_base_url().c_str() + "\".");
- ReportLoadError(error_info);
+ PP_Bool is_data_uri;
+ ErrorInfo error_info;
+ if (!nacl_interface_->RequestNaClManifest(pp_instance(), url.c_str(),
+ &is_data_uri))
return;
- }
- PLUGIN_PRINTF(("Plugin::RequestNaClManifest (resolved url='%s')\n",
- nmf_resolved_url.AsString().c_str()));
- nacl_interface_->SetIsInstalled(
- pp_instance(),
- PP_FromBool(
- nacl_interface_->GetUrlScheme(nmf_resolved_url.pp_var()) ==
- PP_SCHEME_CHROME_EXTENSION));
- set_manifest_base_url(nmf_resolved_url.AsString());
- // Inform JavaScript that a load is starting.
- nacl_interface_->SetNaClReadyState(pp_instance(), PP_NACL_READY_STATE_OPENED);
- EnqueueProgressEvent(PP_NACL_EVENT_LOADSTART);
- bool is_data_uri =
- (nacl_interface_->GetUrlScheme(nmf_resolved_url.pp_var()) ==
- PP_SCHEME_DATA);
- HistogramEnumerateManifestIsDataURI(static_cast<int>(is_data_uri));
+ pp::Var nmf_resolved_url =
+ pp::Var(pp::PASS_REF, nacl_interface_->GetManifestBaseURL(pp_instance()));
if (is_data_uri) {
- pp::CompletionCallback open_callback =
- callback_factory_.NewCallback(&Plugin::NaClManifestBufferReady);
- // Will always call the callback on success or failure.
- CHECK(nexe_downloader_.Open(nmf_resolved_url.AsString(),
- DOWNLOAD_TO_BUFFER,
- open_callback,
- false,
- NULL));
+ std::string string_nmf_resolved_url = nmf_resolved_url.AsString();
+ pp::Var nmf_data = pp::Var(
+ pp::PASS_REF,
+ nacl_interface_->ParseDataURL(string_nmf_resolved_url.c_str()));
+ if (!nmf_data.is_string()) {
+ error_info.SetReport(PP_NACL_ERROR_MANIFEST_LOAD_URL,
+ "could not load manifest url.");
+ ReportLoadError(error_info);
+ } else if (nmf_data.AsString().size() > kNaClManifestMaxFileBytes) {
+ error_info.SetReport(PP_NACL_ERROR_MANIFEST_TOO_LARGE,
+ "manifest file too large.");
+ ReportLoadError(error_info);
+ } else {
+ ProcessNaClManifest(nmf_data.AsString());
+ }
} else {
pp::CompletionCallback open_callback =
callback_factory_.NewCallback(&Plugin::NaClManifestFileDidOpen);
- // Will always call the callback on success or failure.
- CHECK(nexe_downloader_.Open(nmf_resolved_url.AsString(),
- DOWNLOAD_TO_FILE,
- open_callback,
- false,
- NULL));
+ std::string nmf_resolved_url_str = nmf_resolved_url.AsString();
+ nacl_interface_->DownloadManifestToBuffer(
+ pp_instance(),
+ &manifest_data_var_,
+ open_callback.pp_completion_callback());
}
}
-bool Plugin::SetManifestObject(const nacl::string& manifest_json,
- ErrorInfo* error_info) {
+bool Plugin::SetManifestObject(const nacl::string& manifest_json) {
PLUGIN_PRINTF(("Plugin::SetManifestObject(): manifest_json='%s'.\n",
manifest_json.c_str()));
- if (error_info == NULL)
- return false;
// Determine whether lookups should use portable (i.e., pnacl versions)
// rather than platform-specific files.
- bool is_pnacl = (mime_type() == kPnaclMIMEType);
- bool nonsfi_mode_enabled =
- PP_ToBool(nacl_interface_->IsNonSFIModeEnabled());
- bool pnacl_debug = GetNaClInterface()->NaClDebugEnabledForURL(
- manifest_base_url().c_str());
+ bool is_pnacl = nacl_interface_->IsPNaCl(pp_instance());
+ pp::Var manifest_base_url =
+ pp::Var(pp::PASS_REF, nacl_interface_->GetManifestBaseURL(pp_instance()));
+ std::string manifest_base_url_str = manifest_base_url.AsString();
const char* sandbox_isa = nacl_interface_->GetSandboxArch();
- nacl::scoped_ptr<JsonManifest> json_manifest(
- new JsonManifest(url_util_,
- manifest_base_url(),
- (is_pnacl ? kPortableArch : sandbox_isa),
- nonsfi_mode_enabled,
- pnacl_debug));
- if (!json_manifest->Init(manifest_json, error_info)) {
+
+ int32_t manifest_id = nacl_interface_->CreateJsonManifest(
+ pp_instance(),
+ manifest_base_url_str.c_str(),
+ is_pnacl ? kPortableArch : sandbox_isa,
+ manifest_json.c_str());
+ if (manifest_id == -1)
return false;
- }
- manifest_.reset(json_manifest.release());
+ manifest_id_ = manifest_id;
return true;
}
} else if (info->get_desc() > NACL_NO_FILE_DESC) {
std::map<nacl::string, NaClFileInfoAutoCloser*>::iterator it =
url_file_info_map_.find(url_downloader->url());
- if (it != url_file_info_map_.end()) {
+ if (it != url_file_info_map_.end())
delete it->second;
- }
url_file_info_map_[url_downloader->url()] = info;
callback.Run(PP_OK);
} else {
FileDownloader* downloader = new FileDownloader();
downloader->Initialize(this);
url_downloaders_.insert(downloader);
+
// Untrusted loads are always relative to the page's origin.
- CHECK(url_util_ != NULL);
- pp::Var resolved_url =
- url_util_->ResolveRelativeToURL(pp::Var(plugin_base_url()), url);
- if (!resolved_url.is_string()) {
- PLUGIN_PRINTF(("Plugin::StreamAsFile: "
- "could not resolve url \"%s\" relative to plugin \"%s\".",
- url.c_str(),
- plugin_base_url().c_str()));
+ if (!GetNaClInterface()->ResolvesRelativeToPluginBaseUrl(pp_instance(),
+ url.c_str()))
return false;
- }
// Try the fast path first. This will only block if the file is installed.
if (OpenURLFast(url, downloader)) {
}
-void Plugin::ReportLoadSuccess(LengthComputable length_computable,
- uint64_t loaded_bytes,
- uint64_t total_bytes) {
- // Set the readyState attribute to indicate loaded.
- nacl_interface_->SetNaClReadyState(pp_instance(), PP_NACL_READY_STATE_DONE);
- // Inform JavaScript that loading was successful and is complete.
+void Plugin::ReportLoadSuccess(uint64_t loaded_bytes, uint64_t total_bytes) {
const nacl::string& url = nexe_downloader_.url();
- EnqueueProgressEvent(
- PP_NACL_EVENT_LOAD, url, length_computable, loaded_bytes, total_bytes);
- EnqueueProgressEvent(
- PP_NACL_EVENT_LOADEND, url, length_computable, loaded_bytes, total_bytes);
-
- // UMA
- HistogramEnumerateLoadStatus(PP_NACL_ERROR_LOAD_SUCCESS);
+ nacl_interface_->ReportLoadSuccess(
+ pp_instance(), url.c_str(), loaded_bytes, total_bytes);
}
void Plugin::ReportLoadError(const ErrorInfo& error_info) {
- PLUGIN_PRINTF(("Plugin::ReportLoadError (error='%s')\n",
- error_info.message().c_str()));
nacl_interface_->ReportLoadError(pp_instance(),
error_info.error_code(),
error_info.message().c_str(),
void Plugin::ReportLoadAbort() {
- PLUGIN_PRINTF(("Plugin::ReportLoadAbort\n"));
- // Set the readyState attribute to indicate we need to start over.
- nacl_interface()->SetNaClReadyState(pp_instance(), PP_NACL_READY_STATE_DONE);
- nacl_interface()->SetNexeErrorReported(pp_instance(), PP_TRUE);
- // Report an error in lastError and on the JavaScript console.
- nacl::string error_string("NaCl module load failed: user aborted");
- set_last_error_string(error_string);
- nacl_interface()->LogToConsole(pp_instance(), error_string.c_str());
- // Inform JavaScript that loading was aborted and is complete.
- EnqueueProgressEvent(PP_NACL_EVENT_ABORT);
- EnqueueProgressEvent(PP_NACL_EVENT_LOADEND);
-
- // UMA
- HistogramEnumerateLoadStatus(PP_NACL_ERROR_LOAD_ABORTED);
+ nacl_interface_->ReportLoadAbort(pp_instance());
}
void Plugin::UpdateDownloadProgress(
HistogramEnumerateSelLdrLoadStatus(static_cast<NaClErrorCode>(status));
}
-void Plugin::EnqueueProgressEvent(PP_NaClEventType event_type) {
- EnqueueProgressEvent(event_type,
- NACL_NO_URL,
- Plugin::LENGTH_IS_NOT_COMPUTABLE,
- Plugin::kUnknownBytes,
- Plugin::kUnknownBytes);
-}
-
void Plugin::EnqueueProgressEvent(PP_NaClEventType event_type,
const nacl::string& url,
LengthComputable length_computable,
bool Plugin::OpenURLFast(const nacl::string& url,
FileDownloader* downloader) {
- // Fast path only works for installed file URLs.
- pp::Var url_var(url);
- if (nacl_interface_->GetUrlScheme(url_var.pp_var()) !=
- PP_SCHEME_CHROME_EXTENSION)
- return false;
- // IMPORTANT: Make sure the document can request the given URL. If we don't
- // check, a malicious app could probe the extension system. This enforces a
- // same-origin policy which prevents the app from requesting resources from
- // another app.
- if (!DocumentCanRequest(url))
- return false;
-
uint64_t file_token_lo = 0;
uint64_t file_token_hi = 0;
PP_FileHandle file_handle =
}
bool Plugin::DocumentCanRequest(const std::string& url) {
- CHECK(url_util_ != NULL);
- return url_util_->DocumentCanRequest(this, pp::Var(url));
-}
-
-void Plugin::set_last_error_string(const nacl::string& error) {
- DCHECK(nacl_interface_);
- nacl_interface_->SetReadOnlyProperty(pp_instance(),
- pp::Var("lastError").pp_var(),
- pp::Var(error).pp_var());
+ CHECK(pp::Module::Get()->core()->IsMainThread());
+ CHECK(pp::URLUtil_Dev::Get() != NULL);
+ return pp::URLUtil_Dev::Get()->DocumentCanRequest(this, pp::Var(url));
}
void Plugin::set_exit_status(int exit_status) {
int exit_status) {
DCHECK(pp::Module::Get()->core()->IsMainThread());
DCHECK(nacl_interface_);
- exit_status_ = exit_status;
- nacl_interface_->SetReadOnlyProperty(pp_instance(),
- pp::Var("exitStatus").pp_var(),
- pp::Var(exit_status_).pp_var());
+ nacl_interface_->SetExitStatus(pp_instance(), exit_status);
}