diff options
author | miu@chromium.org <miu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-05-05 22:21:14 +0000 |
---|---|---|
committer | miu@chromium.org <miu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-05-05 22:21:14 +0000 |
commit | cbd620bd6d0cb2aae80b5ce945de16b79c55d568 (patch) | |
tree | 3095f2147007c05126f0724d564f6a638e80fa8a /ppapi | |
parent | 78ff793d7b8ae548825b36575150c626166886c8 (diff) | |
download | chromium_src-cbd620bd6d0cb2aae80b5ce945de16b79c55d568.zip chromium_src-cbd620bd6d0cb2aae80b5ce945de16b79c55d568.tar.gz chromium_src-cbd620bd6d0cb2aae80b5ce945de16b79c55d568.tar.bz2 |
Revert 268280 "Pepper: Move manifest logic to components/nacl."
Caused build breakage because static initializer was added to ppb_nacl_private_impl.cc.
Candidate (line 96): + const int32_t kPNaClManifestId = std::numeric_limits<int32_t>::max();
> Pepper: Move manifest logic to components/nacl.
>
> The goal of the trusted plugin refactor is to move as much code as possible out of ppapi/native_client/src/trusted/plugin. This change moves all the manifest parsing and lookup logic out of the trusted plugin at once; it's hard to move piecemeal.
>
> BUG=353592
> R=bbudge@chromium.org, mallinath@chromium.org
>
> Committed: https://src.chromium.org/viewvc/chrome?view=rev&revision=268250
>
> Review URL: https://codereview.chromium.org/264943003
TBR=teravest@chromium.org
Review URL: https://codereview.chromium.org/265393004
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@268295 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ppapi')
16 files changed, 969 insertions, 124 deletions
diff --git a/ppapi/api/private/ppb_nacl_private.idl b/ppapi/api/private/ppb_nacl_private.idl index a1fcb45..04b6758 100644 --- a/ppapi/api/private/ppb_nacl_private.idl +++ b/ppapi/api/private/ppb_nacl_private.idl @@ -411,25 +411,4 @@ interface PPB_NaCl_Private { void DownloadManifestToBuffer([in] PP_Instance instance, [out] PP_Var data, [in] PP_CompletionCallback callback); - - int32_t CreatePnaclManifest([in] PP_Instance instance); - int32_t CreateJsonManifest([in] PP_Instance instance, - [in] str_t manifest_base_url, - [in] str_t sandbox_isa, - [in] str_t manifest_data); - - void DestroyManifest([in] PP_Instance instance, - [in] int32_t manifest_id); - - PP_Bool GetManifestProgramURL([in] PP_Instance instance, - [in] int32_t manifest_id, - [out] PP_Var full_url, - [out] PP_PNaClOptions pnacl_options, - [out] PP_Bool uses_nonsfi_mode); - - PP_Bool ManifestResolveKey([in] PP_Instance instance, - [in] int32_t manifest_id, - [in] str_t key, - [out] PP_Var full_url, - [out] PP_PNaClOptions pnacl_options); }; diff --git a/ppapi/c/private/ppb_nacl_private.h b/ppapi/c/private/ppb_nacl_private.h index bc4a182..9ac540a 100644 --- a/ppapi/c/private/ppb_nacl_private.h +++ b/ppapi/c/private/ppb_nacl_private.h @@ -3,7 +3,7 @@ * found in the LICENSE file. */ -/* From private/ppb_nacl_private.idl modified Mon May 5 10:57:38 2014. */ +/* From private/ppb_nacl_private.idl modified Sat May 3 04:07:13 2014. */ #ifndef PPAPI_C_PRIVATE_PPB_NACL_PRIVATE_H_ #define PPAPI_C_PRIVATE_PPB_NACL_PRIVATE_H_ @@ -407,22 +407,6 @@ struct PPB_NaCl_Private_1_0 { void (*DownloadManifestToBuffer)(PP_Instance instance, struct PP_Var* data, struct PP_CompletionCallback callback); - int32_t (*CreatePnaclManifest)(PP_Instance instance); - int32_t (*CreateJsonManifest)(PP_Instance instance, - const char* manifest_base_url, - const char* sandbox_isa, - const char* manifest_data); - void (*DestroyManifest)(PP_Instance instance, int32_t manifest_id); - PP_Bool (*GetManifestProgramURL)(PP_Instance instance, - int32_t manifest_id, - struct PP_Var* full_url, - struct PP_PNaClOptions* pnacl_options, - PP_Bool* uses_nonsfi_mode); - PP_Bool (*ManifestResolveKey)(PP_Instance instance, - int32_t manifest_id, - const char* key, - struct PP_Var* full_url, - struct PP_PNaClOptions* pnacl_options); }; typedef struct PPB_NaCl_Private_1_0 PPB_NaCl_Private; diff --git a/ppapi/native_client/src/trusted/plugin/json_manifest.cc b/ppapi/native_client/src/trusted/plugin/json_manifest.cc new file mode 100644 index 0000000..418339c --- /dev/null +++ b/ppapi/native_client/src/trusted/plugin/json_manifest.cc @@ -0,0 +1,674 @@ +/* + * Copyright (c) 2012 The Chromium Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include <algorithm> + +#include "ppapi/native_client/src/trusted/plugin/json_manifest.h" + +#include <stdlib.h> + +#include "native_client/src/include/nacl_base.h" +#include "native_client/src/include/nacl_macros.h" +#include "native_client/src/include/nacl_string.h" +#include "native_client/src/include/portability.h" +#include "native_client/src/shared/platform/nacl_check.h" +#include "ppapi/c/private/ppb_nacl_private.h" +#include "ppapi/cpp/dev/url_util_dev.h" +#include "ppapi/cpp/var.h" +#include "ppapi/native_client/src/trusted/plugin/plugin_error.h" +#include "ppapi/native_client/src/trusted/plugin/utility.h" +#include "third_party/jsoncpp/source/include/json/reader.h" + +namespace plugin { + +namespace { +// Top-level section name keys +const char* const kProgramKey = "program"; +const char* const kInterpreterKey = "interpreter"; +const char* const kFilesKey = "files"; + +// ISA Dictionary keys +const char* const kX8632Key = "x86-32"; +const char* const kX8632NonSFIKey = "x86-32-nonsfi"; +const char* const kX8664Key = "x86-64"; +const char* const kX8664NonSFIKey = "x86-64-nonsfi"; +const char* const kArmKey = "arm"; +const char* const kArmNonSFIKey = "arm-nonsfi"; +const char* const kPortableKey = "portable"; + +// Url Resolution keys +const char* const kPnaclDebugKey = "pnacl-debug"; +const char* const kPnaclTranslateKey = "pnacl-translate"; +const char* const kUrlKey = "url"; + +// PNaCl keys +const char* const kOptLevelKey = "optlevel"; + +// Sample NaCl manifest file: +// { +// "program": { +// "x86-32": {"url": "myprogram_x86-32.nexe"}, +// "x86-64": {"url": "myprogram_x86-64.nexe"}, +// "arm": {"url": "myprogram_arm.nexe"} +// }, +// "interpreter": { +// "x86-32": {"url": "interpreter_x86-32.nexe"}, +// "x86-64": {"url": "interpreter_x86-64.nexe"}, +// "arm": {"url": "interpreter_arm.nexe"} +// }, +// "files": { +// "foo.txt": { +// "portable": {"url": "foo.txt"} +// }, +// "bar.txt": { +// "x86-32": {"url": "x86-32/bar.txt"}, +// "portable": {"url": "bar.txt"} +// }, +// "libfoo.so": { +// "x86-64" : { "url": "..." } +// } +// } +// } + +// Sample PNaCl manifest file: +// { +// "program": { +// "portable": { +// "pnacl-translate": { +// "url": "myprogram.pexe" +// }, +// "pnacl-debug": { +// "url": "myprogram.debug.pexe", +// "opt_level": 0 +// } +// } +// }, +// "files": { +// "foo.txt": { +// "portable": {"url": "foo.txt"} +// }, +// "bar.txt": { +// "portable": {"url": "bar.txt"} +// } +// } +// } + +// Returns the key for the architecture in non-SFI mode. +nacl::string GetNonSFIKey(const nacl::string& sandbox_isa) { + return sandbox_isa + "-nonsfi"; +} + +// Looks up |property_name| in the vector |valid_names| with length +// |valid_name_count|. Returns true if |property_name| is found. +bool FindMatchingProperty(const nacl::string& property_name, + const char** valid_names, + size_t valid_name_count) { + for (size_t i = 0; i < valid_name_count; ++i) { + if (property_name == valid_names[i]) { + return true; + } + } + return false; +} + +// Return true if this is a valid dictionary. Having only keys present in +// |valid_keys| and having at least the keys in |required_keys|. +// Error messages will be placed in |error_string|, given that the dictionary +// was the property value of |container_key|. +// E.g., "container_key" : dictionary +bool IsValidDictionary(const Json::Value& dictionary, + const nacl::string& container_key, + const nacl::string& parent_key, + const char** valid_keys, + size_t valid_key_count, + const char** required_keys, + size_t required_key_count, + nacl::string* error_string) { + if (!dictionary.isObject()) { + nacl::stringstream error_stream; + error_stream << parent_key << " property '" << container_key + << "' is non-dictionary value '" + << dictionary.toStyledString() << "'."; + *error_string = error_stream.str(); + return false; + } + // Check for unknown dictionary members. + Json::Value::Members members = dictionary.getMemberNames(); + for (size_t i = 0; i < members.size(); ++i) { + nacl::string property_name = members[i]; + if (!FindMatchingProperty(property_name, + valid_keys, + valid_key_count)) { + // For forward compatibility, we do not prohibit other keys being in + // the dictionary. + PLUGIN_PRINTF(("WARNING: '%s' property '%s' has unknown key '%s'.\n", + parent_key.c_str(), + container_key.c_str(), property_name.c_str())); + } + } + // Check for required members. + for (size_t i = 0; i < required_key_count; ++i) { + if (!dictionary.isMember(required_keys[i])) { + nacl::stringstream error_stream; + error_stream << parent_key << " property '" << container_key + << "' does not have required key: '" + << required_keys[i] << "'."; + *error_string = error_stream.str(); + return false; + } + } + return true; +} + +// Validate a "url" dictionary assuming it was resolved from container_key. +// E.g., "container_key" : { "url": "foo.txt" } +bool IsValidUrlSpec(const Json::Value& url_spec, + const nacl::string& container_key, + const nacl::string& parent_key, + const nacl::string& sandbox_isa, + nacl::string* error_string) { + static const char* kManifestUrlSpecRequired[] = { + kUrlKey + }; + const char** urlSpecPlusOptional; + size_t urlSpecPlusOptionalLength; + if (sandbox_isa == kPortableKey) { + static const char* kPnaclUrlSpecPlusOptional[] = { + kUrlKey, + kOptLevelKey, + }; + urlSpecPlusOptional = kPnaclUrlSpecPlusOptional; + urlSpecPlusOptionalLength = NACL_ARRAY_SIZE(kPnaclUrlSpecPlusOptional); + } else { + // URL specifications must not contain "pnacl-translate" keys. + // This prohibits NaCl clients from invoking PNaCl. + if (url_spec.isMember(kPnaclTranslateKey)) { + nacl::stringstream error_stream; + error_stream << "PNaCl-like NMF with application/x-nacl mimetype instead " + << "of x-pnacl mimetype (has " << kPnaclTranslateKey << ")."; + *error_string = error_stream.str(); + return false; + } + urlSpecPlusOptional = kManifestUrlSpecRequired; + urlSpecPlusOptionalLength = NACL_ARRAY_SIZE(kManifestUrlSpecRequired); + } + if (!IsValidDictionary(url_spec, container_key, parent_key, + urlSpecPlusOptional, + urlSpecPlusOptionalLength, + kManifestUrlSpecRequired, + NACL_ARRAY_SIZE(kManifestUrlSpecRequired), + error_string)) { + return false; + } + // Verify the correct types of the fields if they exist. + Json::Value url = url_spec[kUrlKey]; + if (!url.isString()) { + nacl::stringstream error_stream; + error_stream << parent_key << " property '" << container_key << + "' has non-string value '" << url.toStyledString() << + "' for key '" << kUrlKey << "'."; + *error_string = error_stream.str(); + return false; + } + Json::Value opt_level = url_spec[kOptLevelKey]; + if (!opt_level.empty() && !opt_level.isNumeric()) { + nacl::stringstream error_stream; + error_stream << parent_key << " property '" << container_key << + "' has non-numeric value '" << opt_level.toStyledString() << + "' for key '" << kOptLevelKey << "'."; + *error_string = error_stream.str(); + return false; + } + return true; +} + +// Validate a "pnacl-translate" or "pnacl-debug" dictionary, assuming +// it was resolved from container_key. +// E.g., "container_key" : { "pnacl-translate" : URLSpec } +bool IsValidPnaclTranslateSpec(const Json::Value& pnacl_spec, + const nacl::string& container_key, + const nacl::string& parent_key, + const nacl::string& sandbox_isa, + nacl::string* error_string) { + static const char* kManifestPnaclSpecValid[] = { + kPnaclDebugKey, + kPnaclTranslateKey + }; + static const char* kManifestPnaclSpecRequired[] = { + kPnaclTranslateKey + }; + if (!IsValidDictionary(pnacl_spec, container_key, parent_key, + kManifestPnaclSpecValid, + NACL_ARRAY_SIZE(kManifestPnaclSpecValid), + kManifestPnaclSpecRequired, + NACL_ARRAY_SIZE(kManifestPnaclSpecRequired), + error_string)) { + return false; + } + Json::Value url_spec = pnacl_spec[kPnaclTranslateKey]; + if (!IsValidUrlSpec(url_spec, kPnaclTranslateKey, + container_key, sandbox_isa, error_string)) { + return false; + } + return true; +} + +// Validates that |dictionary| is a valid ISA dictionary. An ISA dictionary +// is validated to have keys from within the set of recognized ISAs. Unknown +// ISAs are allowed, but ignored and warnings are produced. It is also validated +// that it must have an entry to match the ISA specified in |sandbox_isa| or +// have a fallback 'portable' entry if there is no match. Returns true if +// |dictionary| is an ISA to URL map. Sets |error_info| to something +// descriptive if it fails. +bool IsValidISADictionary(const Json::Value& dictionary, + const nacl::string& parent_key, + const nacl::string& sandbox_isa, + bool must_find_matching_entry, + bool nonsfi_enabled, + ErrorInfo* error_info) { + if (error_info == NULL) return false; + + // An ISA to URL dictionary has to be an object. + if (!dictionary.isObject()) { + error_info->SetReport(PP_NACL_ERROR_MANIFEST_SCHEMA_VALIDATE, + nacl::string("manifest: ") + parent_key + + " property is not an ISA to URL dictionary"); + return false; + } + // Build the set of reserved ISA dictionary keys. + const char** isaProperties; + size_t isaPropertiesLength; + if (sandbox_isa == kPortableKey) { + // The known values for PNaCl ISA dictionaries in the manifest. + static const char* kPnaclManifestISAProperties[] = { + kPortableKey + }; + isaProperties = kPnaclManifestISAProperties; + isaPropertiesLength = NACL_ARRAY_SIZE(kPnaclManifestISAProperties); + } else { + // The known values for NaCl ISA dictionaries in the manifest. + static const char* kNaClManifestISAProperties[] = { + kX8632Key, + kX8632NonSFIKey, + kX8664Key, + kX8664NonSFIKey, + kArmKey, + kArmNonSFIKey, + // "portable" is here to allow checking that, if present, it can + // only refer to an URL, such as for a data file, and not to + // "pnacl-translate", which would cause the creation of a nexe. + kPortableKey + }; + isaProperties = kNaClManifestISAProperties; + isaPropertiesLength = NACL_ARRAY_SIZE(kNaClManifestISAProperties); + } + // Check that entries in the dictionary are structurally correct. + Json::Value::Members members = dictionary.getMemberNames(); + for (size_t i = 0; i < members.size(); ++i) { + nacl::string property_name = members[i]; + Json::Value property_value = dictionary[property_name]; + nacl::string error_string; + if (FindMatchingProperty(property_name, + isaProperties, + isaPropertiesLength)) { + // For NaCl, arch entries can only be + // "arch/portable" : URLSpec + // For PNaCl arch in "program" dictionary entries can be + // "portable" : { "pnacl-translate": URLSpec } + // or "portable" : { "pnacl-debug": URLSpec } + // For PNaCl arch elsewhere, dictionary entries can only be + // "portable" : URLSpec + if ((sandbox_isa != kPortableKey && + !IsValidUrlSpec(property_value, property_name, parent_key, + sandbox_isa, &error_string)) || + (sandbox_isa == kPortableKey && + parent_key == kProgramKey && + !IsValidPnaclTranslateSpec(property_value, property_name, parent_key, + sandbox_isa, &error_string)) || + (sandbox_isa == kPortableKey && + parent_key != kProgramKey && + !IsValidUrlSpec(property_value, property_name, parent_key, + sandbox_isa, &error_string))) { + error_info->SetReport(PP_NACL_ERROR_MANIFEST_SCHEMA_VALIDATE, + nacl::string("manifest: ") + error_string); + return false; + } + } else { + // For forward compatibility, we do not prohibit other keys being in + // the dictionary, as they may be architectures supported in later + // versions. However, the value of these entries must be an URLSpec. + PLUGIN_PRINTF(("IsValidISADictionary: unrecognized key '%s'.\n", + property_name.c_str())); + if (!IsValidUrlSpec(property_value, property_name, parent_key, + sandbox_isa, &error_string)) { + error_info->SetReport(PP_NACL_ERROR_MANIFEST_SCHEMA_VALIDATE, + nacl::string("manifest: ") + error_string); + return false; + } + } + } + + if (sandbox_isa == kPortableKey) { + bool has_portable = dictionary.isMember(kPortableKey); + + if (!has_portable) { + error_info->SetReport( + PP_NACL_ERROR_MANIFEST_PROGRAM_MISSING_ARCH, + nacl::string("manifest: no version of ") + parent_key + + " given for portable."); + return false; + } + } else if (must_find_matching_entry) { + // TODO(elijahtaylor) add ISA resolver here if we expand ISAs to include + // micro-architectures that can resolve to multiple valid sandboxes. + bool has_isa = dictionary.isMember(sandbox_isa); + bool has_nonsfi_isa = + nonsfi_enabled && dictionary.isMember(GetNonSFIKey(sandbox_isa)); + bool has_portable = dictionary.isMember(kPortableKey); + + if (!has_isa && !has_nonsfi_isa && !has_portable) { + error_info->SetReport( + PP_NACL_ERROR_MANIFEST_PROGRAM_MISSING_ARCH, + nacl::string("manifest: no version of ") + parent_key + + " given for current arch and no portable version found."); + return false; + } + } + + return true; +} + +void GrabUrlAndPNaClOptions(const Json::Value& url_spec, + nacl::string* url, + PP_PNaClOptions* pnacl_options) { + *url = url_spec[kUrlKey].asString(); + pnacl_options->translate = PP_TRUE; + if (url_spec.isMember(kOptLevelKey)) { + int32_t opt_raw = url_spec[kOptLevelKey].asInt(); + int32_t opt_level; + // Currently only allow 0 or 2, since that is what we test. + if (opt_raw <= 0) + opt_level = 0; + else + opt_level = 2; + pnacl_options->opt_level = opt_level; + } +} + +} // namespace + +bool JsonManifest::Init(const nacl::string& manifest_json, + ErrorInfo* error_info) { + if (error_info == NULL) { + return false; + } + Json::Reader reader; + if (!reader.parse(manifest_json, dictionary_)) { + std::string json_error = reader.getFormatedErrorMessages(); + error_info->SetReport(PP_NACL_ERROR_MANIFEST_PARSING, + "manifest JSON parsing failed: " + json_error); + return false; + } + // Parse has ensured the string was valid JSON. Check that it matches the + // manifest schema. + return MatchesSchema(error_info); +} + +bool JsonManifest::MatchesSchema(ErrorInfo* error_info) { + pp::Var exception; + if (error_info == NULL) { + return false; + } + if (!dictionary_.isObject()) { + error_info->SetReport( + PP_NACL_ERROR_MANIFEST_SCHEMA_VALIDATE, + "manifest: is not a json dictionary."); + return false; + } + Json::Value::Members members = dictionary_.getMemberNames(); + for (size_t i = 0; i < members.size(); ++i) { + // The top level dictionary entries valid in the manifest file. + static const char* kManifestTopLevelProperties[] = { kProgramKey, + kInterpreterKey, + kFilesKey }; + nacl::string property_name = members[i]; + if (!FindMatchingProperty(property_name, + kManifestTopLevelProperties, + NACL_ARRAY_SIZE(kManifestTopLevelProperties))) { + PLUGIN_PRINTF(("JsonManifest::MatchesSchema: WARNING: unknown top-level " + "section '%s' in manifest.\n", property_name.c_str())); + } + } + + // A manifest file must have a program section. + if (!dictionary_.isMember(kProgramKey)) { + error_info->SetReport( + PP_NACL_ERROR_MANIFEST_SCHEMA_VALIDATE, + nacl::string("manifest: missing '") + kProgramKey + "' section."); + return false; + } + + // Validate the program section. + // There must be a matching (portable or sandbox_isa_) entry for program for + // NaCl. + if (!IsValidISADictionary(dictionary_[kProgramKey], + kProgramKey, + sandbox_isa_, + true, + nonsfi_enabled_, + error_info)) { + return false; + } + + // Validate the interpreter section (if given). + // There must be a matching (portable or sandbox_isa_) entry for interpreter + // for NaCl. + if (dictionary_.isMember(kInterpreterKey)) { + if (!IsValidISADictionary(dictionary_[kInterpreterKey], + kInterpreterKey, + sandbox_isa_, + true, + nonsfi_enabled_, + error_info)) { + return false; + } + } + + // Validate the file dictionary (if given). + // The "files" key does not require a matching (portable or sandbox_isa_) + // entry at schema validation time for NaCl. This allows manifests to specify + // resources that are only loaded for a particular sandbox_isa. + if (dictionary_.isMember(kFilesKey)) { + const Json::Value& files = dictionary_[kFilesKey]; + if (!files.isObject()) { + error_info->SetReport( + PP_NACL_ERROR_MANIFEST_SCHEMA_VALIDATE, + nacl::string("manifest: '") + kFilesKey + "' is not a dictionary."); + } + Json::Value::Members members = files.getMemberNames(); + for (size_t i = 0; i < members.size(); ++i) { + nacl::string file_name = members[i]; + if (!IsValidISADictionary(files[file_name], + file_name, + sandbox_isa_, + false, + nonsfi_enabled_, + error_info)) { + return false; + } + } + } + + return true; +} + +bool JsonManifest::GetURLFromISADictionary(const Json::Value& dictionary, + const nacl::string& parent_key, + nacl::string* url, + PP_PNaClOptions* pnacl_options, + bool* uses_nonsfi_mode, + ErrorInfo* error_info) const { + DCHECK(url != NULL && pnacl_options != NULL && error_info != NULL); + + // When the application actually requests a resolved URL, we must have + // a matching entry (sandbox_isa_ or portable) for NaCl. + ErrorInfo ignored_error_info; + if (!IsValidISADictionary(dictionary, parent_key, sandbox_isa_, true, + nonsfi_enabled_, &ignored_error_info)) { + error_info->SetReport(PP_NACL_ERROR_MANIFEST_RESOLVE_URL, + "architecture " + sandbox_isa_ + + " is not found for file " + parent_key); + return false; + } + + // The call to IsValidISADictionary() above guarantees that either + // sandbox_isa_, its nonsfi mode, or kPortableKey is present in the + // dictionary. + *uses_nonsfi_mode = false; + nacl::string chosen_isa; + if (sandbox_isa_ == kPortableKey) { + chosen_isa = kPortableKey; + } else { + nacl::string nonsfi_isa = GetNonSFIKey(sandbox_isa_); + if (nonsfi_enabled_ && dictionary.isMember(nonsfi_isa)) { + chosen_isa = nonsfi_isa; + *uses_nonsfi_mode = true; + } else if (dictionary.isMember(sandbox_isa_)) { + chosen_isa = sandbox_isa_; + } else if (dictionary.isMember(kPortableKey)) { + chosen_isa = kPortableKey; + } else { + // Should not reach here, because the earlier IsValidISADictionary() + // call checked that the manifest covers the current architecture. + DCHECK(false); + } + } + + const Json::Value& isa_spec = dictionary[chosen_isa]; + // If the PNaCl debug flag is turned on, look for pnacl-debug entries first. + // If found, mark that it is a debug URL. Otherwise, fall back to + // checking for pnacl-translate URLs, etc. and don't mark it as a debug URL. + if (pnacl_debug_ && isa_spec.isMember(kPnaclDebugKey)) { + GrabUrlAndPNaClOptions(isa_spec[kPnaclDebugKey], url, pnacl_options); + pnacl_options->is_debug = PP_TRUE; + } else if (isa_spec.isMember(kPnaclTranslateKey)) { + GrabUrlAndPNaClOptions(isa_spec[kPnaclTranslateKey], url, pnacl_options); + } else { + // NaCl + *url = isa_spec[kUrlKey].asString(); + pnacl_options->translate = PP_FALSE; + } + + return true; +} + +bool JsonManifest::GetKeyUrl(const Json::Value& dictionary, + const nacl::string& key, + nacl::string* full_url, + PP_PNaClOptions* pnacl_options) const { + DCHECK(full_url != NULL && pnacl_options != NULL); + if (!dictionary.isMember(key)) { + PLUGIN_PRINTF(("file key not found in manifest")); + return false; + } + const Json::Value& isa_dict = dictionary[key]; + nacl::string relative_url; + bool uses_nonsfi_mode; + + // We ignore the error_info we receive here but it's needed for the calls + // below. + ErrorInfo error_info; + + if (!GetURLFromISADictionary(isa_dict, key, &relative_url, + pnacl_options, &uses_nonsfi_mode, &error_info)) { + return false; + } + return ResolveURL(relative_url, full_url, &error_info); +} + +bool JsonManifest::GetProgramURL(nacl::string* full_url, + PP_PNaClOptions* pnacl_options, + bool* uses_nonsfi_mode, + ErrorInfo* error_info) const { + if (full_url == NULL || pnacl_options == NULL || error_info == NULL) + return false; + + const Json::Value& program = dictionary_[kProgramKey]; + nacl::string nexe_url; + if (!GetURLFromISADictionary(program, + kProgramKey, + &nexe_url, + pnacl_options, + uses_nonsfi_mode, + error_info)) { + return false; + } + return ResolveURL(nexe_url, full_url, error_info); +} + +bool JsonManifest::ResolveKey(const nacl::string& key, + nacl::string* full_url, + PP_PNaClOptions* pnacl_options) const { + NaClLog(3, "JsonManifest::ResolveKey(%s)\n", key.c_str()); + // key must be one of kProgramKey or kFileKey '/' file-section-key + + if (full_url == NULL || pnacl_options == NULL) + return false; + + if (key == kProgramKey) + return GetKeyUrl(dictionary_, key, full_url, pnacl_options); + nacl::string::const_iterator p = find(key.begin(), key.end(), '/'); + if (p == key.end()) { + std::string err = "ResolveKey: invalid key, no slash: " + key; + PLUGIN_PRINTF((err.c_str())); + return false; + } + + // generalize to permit other sections? + nacl::string prefix(key.begin(), p); + if (prefix != kFilesKey) { + std::string err = "ResolveKey: invalid key: no \"files\" prefix: " + key; + PLUGIN_PRINTF((err.c_str())); + return false; + } + + nacl::string rest(p + 1, key.end()); + + const Json::Value& files = dictionary_[kFilesKey]; + if (!files.isObject()) { + std::string err = "ResolveKey: no \"files\" dictionary"; + PLUGIN_PRINTF((err.c_str())); + return false; + } + if (!files.isMember(rest)) { + std::string err = "ResolveKey: no such \"files\" entry: " + key; + PLUGIN_PRINTF((err.c_str())); + return false; + } + return GetKeyUrl(files, rest, full_url, pnacl_options); +} + +bool JsonManifest::ResolveURL(const nacl::string& relative_url, + nacl::string* full_url, + ErrorInfo* error_info) const { + // The contents of the manifest are resolved relative to the manifest URL. + CHECK(url_util_ != NULL); + pp::Var resolved_url = + url_util_->ResolveRelativeToURL(pp::Var(manifest_base_url_), + relative_url); + if (!resolved_url.is_string()) { + error_info->SetReport( + PP_NACL_ERROR_MANIFEST_RESOLVE_URL, + "could not resolve url '" + relative_url + + "' relative to manifest base url '" + manifest_base_url_.c_str() + + "'."); + return false; + } + *full_url = resolved_url.AsString(); + return true; +} + +} // namespace plugin diff --git a/ppapi/native_client/src/trusted/plugin/json_manifest.h b/ppapi/native_client/src/trusted/plugin/json_manifest.h new file mode 100644 index 0000000..cf02798 --- /dev/null +++ b/ppapi/native_client/src/trusted/plugin/json_manifest.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2012 The Chromium Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +// Manifest processing for JSON manifests. + +#ifndef NATIVE_CLIENT_SRC_TRUSTED_PLUGIN_JSON_MANIFEST_H_ +#define NATIVE_CLIENT_SRC_TRUSTED_PLUGIN_JSON_MANIFEST_H_ + +#include <map> +#include <set> +#include <string> + +#include "native_client/src/include/nacl_macros.h" +#include "native_client/src/include/nacl_string.h" +#include "ppapi/native_client/src/trusted/plugin/manifest.h" +#include "third_party/jsoncpp/source/include/json/value.h" + +struct PP_PNaClOptions; + +namespace pp { +class URLUtil_Dev; +} // namespace pp + +namespace plugin { + +class ErrorInfo; + +class JsonManifest : public Manifest { + public: + JsonManifest(const pp::URLUtil_Dev* url_util, + const nacl::string& manifest_base_url, + const nacl::string& sandbox_isa, + bool nonsfi_enabled, + bool pnacl_debug) + : url_util_(url_util), + manifest_base_url_(manifest_base_url), + sandbox_isa_(sandbox_isa), + nonsfi_enabled_(nonsfi_enabled), + pnacl_debug_(pnacl_debug), + dictionary_(Json::nullValue) { } + virtual ~JsonManifest() { } + + // Initialize the manifest object for use by later lookups. The return + // value is true if the manifest parses correctly and matches the schema. + bool Init(const nacl::string& json, ErrorInfo* error_info); + + // Gets the full program URL for the current sandbox ISA from the + // manifest file. + virtual bool GetProgramURL(nacl::string* full_url, + PP_PNaClOptions* pnacl_options, + bool* uses_nonsfi_mode, + ErrorInfo* error_info) const; + + // Resolves a key from the "files" section to a fully resolved URL, + // i.e., relative URL values are fully expanded relative to the + // manifest's URL (via ResolveURL). + virtual bool ResolveKey(const nacl::string& key, + nacl::string* full_url, + PP_PNaClOptions* pnacl_options) const; + + private: + NACL_DISALLOW_COPY_AND_ASSIGN(JsonManifest); + + // Resolves a URL relative to the manifest base URL + bool ResolveURL(const nacl::string& relative_url, + nacl::string* full_url, + ErrorInfo* error_info) const; + + // Checks that |dictionary_| is a valid manifest, according to the schema. + // Returns true on success, and sets |error_info| to a detailed message + // if not. + bool MatchesSchema(ErrorInfo* error_info); + + bool GetKeyUrl(const Json::Value& dictionary, + const nacl::string& key, + nacl::string* full_url, + PP_PNaClOptions* pnacl_options) const; + + bool GetURLFromISADictionary(const Json::Value& dictionary, + const nacl::string& parent_key, + nacl::string* url, + PP_PNaClOptions* pnacl_options, + bool* uses_nonsfi_mode, + ErrorInfo* error_info) const; + + const pp::URLUtil_Dev* url_util_; + nacl::string manifest_base_url_; + nacl::string sandbox_isa_; + bool nonsfi_enabled_; + bool pnacl_debug_; + + Json::Value dictionary_; +}; + +} // namespace plugin + +#endif // NATIVE_CLIENT_SRC_TRUSTED_PLUGIN_JSON_MANIFEST_H_ diff --git a/ppapi/native_client/src/trusted/plugin/manifest.h b/ppapi/native_client/src/trusted/plugin/manifest.h new file mode 100644 index 0000000..6a74dd6 --- /dev/null +++ b/ppapi/native_client/src/trusted/plugin/manifest.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2012 The Chromium Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +// Manifest interface class. + +#ifndef NATIVE_CLIENT_SRC_TRUSTED_PLUGIN_MANIFEST_H_ +#define NATIVE_CLIENT_SRC_TRUSTED_PLUGIN_MANIFEST_H_ + +#include <map> +#include <set> +#include <string> + +#include "native_client/src/include/nacl_macros.h" +#include "native_client/src/include/nacl_string.h" +#include "third_party/jsoncpp/source/include/json/value.h" + +struct PP_PNaClOptions; + +namespace pp { +class URLUtil_Dev; +} // namespace pp + +namespace plugin { + +class ErrorInfo; + +class Manifest { + public: + Manifest() { } + virtual ~Manifest() { } + + // A convention in the interfaces below regarding permit_extension_url: + // Some manifests (e.g., the pnacl coordinator manifest) need to access + // resources from an extension origin distinct from the plugin's origin + // (e.g., the pnacl coordinator needs to load llc, ld, and some libraries). + // This out-parameter is true if this manifest lookup confers access to + // a resource in the extension origin. + + // Gets the full program URL for the current sandbox ISA from the + // manifest file. Fills in |pnacl_options| if the program requires + // PNaCl translation. + virtual bool GetProgramURL(nacl::string* full_url, + PP_PNaClOptions* pnacl_options, + bool* uses_nonsfi_mode, + ErrorInfo* error_info) const = 0; + + // Resolves a key from the "files" section to a fully resolved URL, + // i.e., relative URL values are fully expanded relative to the + // manifest's URL. Fills in |pnacl_options| if + // the resolved key requires a pnacl translation step to obtain + // the final requested resource. + virtual bool ResolveKey(const nacl::string& key, + nacl::string* full_url, + PP_PNaClOptions* pnacl_options) const = 0; + + protected: + NACL_DISALLOW_COPY_AND_ASSIGN(Manifest); +}; + + +} // namespace plugin + +#endif // NATIVE_CLIENT_SRC_TRUSTED_PLUGIN_MANIFEST_H_ diff --git a/ppapi/native_client/src/trusted/plugin/plugin.cc b/ppapi/native_client/src/trusted/plugin/plugin.cc index ce2d4ba..071e534 100644 --- a/ppapi/native_client/src/trusted/plugin/plugin.cc +++ b/ppapi/native_client/src/trusted/plugin/plugin.cc @@ -34,6 +34,7 @@ #include "ppapi/cpp/dev/url_util_dev.h" #include "ppapi/cpp/module.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" @@ -135,11 +136,11 @@ void Plugin::HistogramHTTPStatusCode(const std::string& name, int status) { bool Plugin::LoadNaClModuleFromBackgroundThread( nacl::DescWrapper* wrapper, NaClSubprocess* subprocess, - int32_t manifest_id, + const Manifest* manifest, const SelLdrStartParams& params) { CHECK(!pp::Module::Get()->core()->IsMainThread()); ServiceRuntime* service_runtime = - new ServiceRuntime(this, manifest_id, false, uses_nonsfi_mode_, + new ServiceRuntime(this, manifest, false, uses_nonsfi_mode_, pp::BlockUntilComplete(), pp::BlockUntilComplete()); subprocess->set_service_runtime(service_runtime); PLUGIN_PRINTF(("Plugin::LoadNaClModuleFromBackgroundThread " @@ -227,7 +228,7 @@ void Plugin::LoadNaClModule(nacl::DescWrapper* wrapper, enable_crash_throttling); ErrorInfo error_info; ServiceRuntime* service_runtime = - new ServiceRuntime(this, manifest_id_, true, uses_nonsfi_mode, + new ServiceRuntime(this, manifest_.get(), true, uses_nonsfi_mode, init_done_cb, crash_cb); main_subprocess_.set_service_runtime(service_runtime); PLUGIN_PRINTF(("Plugin::LoadNaClModule (service_runtime=%p)\n", @@ -292,7 +293,7 @@ bool Plugin::LoadNaClModuleContinuationIntern() { NaClSubprocess* Plugin::LoadHelperNaClModule(const nacl::string& helper_url, nacl::DescWrapper* wrapper, - int32_t manifest_id, + const Manifest* manifest, ErrorInfo* error_info) { nacl::scoped_ptr<NaClSubprocess> nacl_subprocess( new NaClSubprocess("helper module", NULL, NULL)); @@ -319,7 +320,7 @@ NaClSubprocess* Plugin::LoadHelperNaClModule(const nacl::string& helper_url, false /* enable_exception_handling */, true /* enable_crash_throttling */); if (!LoadNaClModuleFromBackgroundThread(wrapper, nacl_subprocess.get(), - manifest_id, params)) { + manifest, params)) { return NULL; } // We need not wait for the init_done callback. We can block @@ -369,7 +370,6 @@ Plugin::Plugin(PP_Instance pp_instance) wrapper_factory_(NULL), time_of_last_progress_event_(0), nexe_open_time_(-1), - manifest_id_(-1), nacl_interface_(NULL), uma_interface_(this) { PLUGIN_PRINTF(("Plugin::Plugin (this=%p, pp_instance=%" @@ -580,19 +580,20 @@ void Plugin::ProcessNaClManifest(const nacl::string& manifest_json) { if (!SetManifestObject(manifest_json)) return; - PP_Var pp_program_url; + nacl::string 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(); + bool uses_nonsfi_mode; + ErrorInfo error_info; + if (manifest_->GetProgramURL( + &program_url, &pnacl_options, &uses_nonsfi_mode, &error_info)) { // 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); + uses_nonsfi_mode_ = 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, @@ -618,6 +619,8 @@ void Plugin::ProcessNaClManifest(const nacl::string& manifest_json) { return; } } + // Failed to select the program and/or the translator. + ReportLoadError(error_info); } void Plugin::RequestNaClManifest(const nacl::string& url) { @@ -660,22 +663,30 @@ void Plugin::RequestNaClManifest(const nacl::string& url) { bool Plugin::SetManifestObject(const nacl::string& manifest_json) { PLUGIN_PRINTF(("Plugin::SetManifestObject(): manifest_json='%s'.\n", manifest_json.c_str())); + ErrorInfo error_info; + // Determine whether lookups should use portable (i.e., pnacl versions) // rather than platform-specific files. bool is_pnacl = nacl_interface_->IsPNaCl(pp_instance()); + bool nonsfi_mode_enabled = + PP_ToBool(nacl_interface_->IsNonSFIModeEnabled()); 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 pnacl_debug = GetNaClInterface()->NaClDebugEnabledForURL( + manifest_base_url_str.c_str()); const char* sandbox_isa = nacl_interface_->GetSandboxArch(); - - 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) + nacl::scoped_ptr<JsonManifest> json_manifest( + new JsonManifest(pp::URLUtil_Dev::Get(), + manifest_base_url_str, + (is_pnacl ? kPortableArch : sandbox_isa), + nonsfi_mode_enabled, + pnacl_debug)); + if (!json_manifest->Init(manifest_json, &error_info)) { + ReportLoadError(error_info); return false; - manifest_id_ = manifest_id; + } + manifest_.reset(json_manifest.release()); return true; } diff --git a/ppapi/native_client/src/trusted/plugin/plugin.gypi b/ppapi/native_client/src/trusted/plugin/plugin.gypi index 15e2d19..d9de561 100644 --- a/ppapi/native_client/src/trusted/plugin/plugin.gypi +++ b/ppapi/native_client/src/trusted/plugin/plugin.gypi @@ -8,6 +8,7 @@ 'common_sources': [ 'file_downloader.cc', 'file_utils.cc', + 'json_manifest.cc', 'module_ppapi.cc', 'nacl_subprocess.cc', 'plugin.cc', diff --git a/ppapi/native_client/src/trusted/plugin/plugin.h b/ppapi/native_client/src/trusted/plugin/plugin.h index 1978be7..c573bd2 100644 --- a/ppapi/native_client/src/trusted/plugin/plugin.h +++ b/ppapi/native_client/src/trusted/plugin/plugin.h @@ -111,7 +111,7 @@ class Plugin : public pp::Instance { // Returns NULL or the NaClSubprocess of the new helper NaCl module. NaClSubprocess* LoadHelperNaClModule(const nacl::string& helper_url, nacl::DescWrapper* wrapper, - int32_t manifest_id, + const Manifest* manifest, ErrorInfo* error_info); enum LengthComputable { @@ -164,6 +164,8 @@ class Plugin : public pp::Instance { // document to request the URL using CORS even if this function returns false. bool DocumentCanRequest(const std::string& url); + Manifest const* manifest() const { return manifest_.get(); } + // set_exit_status may be called off the main thread. void set_exit_status(int exit_status); @@ -204,7 +206,7 @@ class Plugin : public pp::Instance { // This will fully initialize the |subprocess| if the load was successful. bool LoadNaClModuleFromBackgroundThread(nacl::DescWrapper* wrapper, NaClSubprocess* subprocess, - int32_t manifest_id, + const Manifest* manifest, const SelLdrStartParams& params); // Start sel_ldr from the main thread, given the start params. @@ -302,6 +304,9 @@ class Plugin : public pp::Instance { nacl::scoped_ptr<PnaclCoordinator> pnacl_coordinator_; + // The manifest dictionary. Used for looking up resources to be loaded. + nacl::scoped_ptr<Manifest> manifest_; + // Keep track of the FileDownloaders created to fetch urls. std::set<FileDownloader*> url_downloaders_; // Keep track of file descriptors opened by StreamAsFile(). @@ -329,7 +334,6 @@ class Plugin : public pp::Instance { int64_t nexe_open_time_; PP_Var manifest_data_var_; - int32_t manifest_id_; const PPB_NaCl_Private* nacl_interface_; pp::UMAPrivate uma_interface_; diff --git a/ppapi/native_client/src/trusted/plugin/pnacl_coordinator.cc b/ppapi/native_client/src/trusted/plugin/pnacl_coordinator.cc index 626536a..93d2220 100644 --- a/ppapi/native_client/src/trusted/plugin/pnacl_coordinator.cc +++ b/ppapi/native_client/src/trusted/plugin/pnacl_coordinator.cc @@ -16,6 +16,7 @@ #include "ppapi/c/pp_errors.h" #include "ppapi/c/private/ppb_uma_private.h" +#include "ppapi/native_client/src/trusted/plugin/manifest.h" #include "ppapi/native_client/src/trusted/plugin/plugin.h" #include "ppapi/native_client/src/trusted/plugin/plugin_error.h" #include "ppapi/native_client/src/trusted/plugin/pnacl_translate_thread.h" @@ -25,6 +26,62 @@ namespace plugin { ////////////////////////////////////////////////////////////////////// +// Pnacl-specific manifest support. +////////////////////////////////////////////////////////////////////// + +// The PNaCl linker gets file descriptors via the service runtime's +// reverse service lookup. The reverse service lookup requires a manifest. +// Normally, that manifest is an NMF containing mappings for shared libraries. +// Here, we provide a manifest that redirects to PNaCl component files +// that are part of Chrome. +class PnaclManifest : public Manifest { + public: + PnaclManifest(const nacl::string& sandbox_arch) + : sandbox_arch_(sandbox_arch) { } + + virtual ~PnaclManifest() { } + + virtual bool GetProgramURL(nacl::string* full_url, + PP_PNaClOptions* pnacl_options, + bool* uses_nonsfi_mode, + ErrorInfo* error_info) const { + // Does not contain program urls. + UNREFERENCED_PARAMETER(full_url); + UNREFERENCED_PARAMETER(pnacl_options); + UNREFERENCED_PARAMETER(uses_nonsfi_mode); + UNREFERENCED_PARAMETER(error_info); + PLUGIN_PRINTF(("PnaclManifest does not contain a program\n")); + error_info->SetReport(PP_NACL_ERROR_MANIFEST_GET_NEXE_URL, + "pnacl manifest does not contain a program."); + return false; + } + + virtual bool ResolveKey(const nacl::string& key, + nacl::string* full_url, + PP_PNaClOptions* pnacl_options) const { + // All of the component files are native (do not require pnacl translate). + pnacl_options->translate = PP_FALSE; + // We can only resolve keys in the files/ namespace. + const nacl::string kFilesPrefix = "files/"; + size_t files_prefix_pos = key.find(kFilesPrefix); + if (files_prefix_pos == nacl::string::npos) { + PLUGIN_PRINTF(("key did not start with files/")); + return false; + } + // Resolve the full URL to the file. Provide it with a platform-specific + // prefix. + nacl::string key_basename = key.substr(kFilesPrefix.length()); + *full_url = PnaclUrls::GetBaseUrl() + sandbox_arch_ + "/" + key_basename; + return true; + } + + private: + NACL_DISALLOW_COPY_AND_ASSIGN(PnaclManifest); + + nacl::string sandbox_arch_; +}; + +////////////////////////////////////////////////////////////////////// // UMA stat helpers. ////////////////////////////////////////////////////////////////////// @@ -123,10 +180,10 @@ PnaclCoordinator* PnaclCoordinator::BitcodeToNative( new PnaclCoordinator(plugin, pexe_url, pnacl_options, translate_notify_callback); - PLUGIN_PRINTF(("PnaclCoordinator::BitcodeToNative (manifest_id=%d)\n", - coordinator->manifest_id_)); - coordinator->pnacl_init_time_ = NaClGetTimeOfDayMicroseconds(); + PLUGIN_PRINTF(("PnaclCoordinator::BitcodeToNative (manifest=%p, ", + reinterpret_cast<const void*>(coordinator->manifest_.get()))); + int cpus = plugin->nacl_interface()->GetNumberOfProcessors(); coordinator->split_module_count_ = std::min(4, std::max(1, cpus)); @@ -147,8 +204,7 @@ PnaclCoordinator::PnaclCoordinator( plugin_(plugin), translate_notify_callback_(translate_notify_callback), translation_finished_reported_(false), - manifest_id_( - GetNaClInterface()->CreatePnaclManifest(plugin->pp_instance())), + manifest_(new PnaclManifest(plugin->nacl_interface()->GetSandboxArch())), pexe_url_(pexe_url), pnacl_options_(pnacl_options), split_module_count_(1), @@ -612,7 +668,7 @@ void PnaclCoordinator::RunTranslate(int32_t pp_error) { CHECK(translate_thread_ != NULL); translate_thread_->RunTranslate(report_translate_finished, - manifest_id_, + manifest_.get(), &obj_files_, temp_nexe_file_.get(), invalid_desc_wrapper_.get(), diff --git a/ppapi/native_client/src/trusted/plugin/pnacl_coordinator.h b/ppapi/native_client/src/trusted/plugin/pnacl_coordinator.h index 954bb09..99d6e70 100644 --- a/ppapi/native_client/src/trusted/plugin/pnacl_coordinator.h +++ b/ppapi/native_client/src/trusted/plugin/pnacl_coordinator.h @@ -27,6 +27,7 @@ struct PP_PNaClOptions; namespace plugin { +class Manifest; class Plugin; class PnaclCoordinator; class PnaclTranslateThread; @@ -203,7 +204,7 @@ class PnaclCoordinator: public CallbackSource<FileStreamData> { // The manifest used by resource loading and ld + llc's reverse service // to look up objects and libraries. - int32_t manifest_id_; + nacl::scoped_ptr<const Manifest> manifest_; // An auxiliary class that manages downloaded resources (llc and ld nexes). nacl::scoped_ptr<PnaclResources> resources_; diff --git a/ppapi/native_client/src/trusted/plugin/pnacl_resources.cc b/ppapi/native_client/src/trusted/plugin/pnacl_resources.cc index 747d147..160066b 100644 --- a/ppapi/native_client/src/trusted/plugin/pnacl_resources.cc +++ b/ppapi/native_client/src/trusted/plugin/pnacl_resources.cc @@ -9,6 +9,7 @@ #include "native_client/src/trusted/desc/nacl_desc_wrapper.h" #include "ppapi/c/pp_errors.h" #include "ppapi/native_client/src/trusted/plugin/file_utils.h" +#include "ppapi/native_client/src/trusted/plugin/manifest.h" #include "ppapi/native_client/src/trusted/plugin/plugin.h" #include "ppapi/native_client/src/trusted/plugin/pnacl_coordinator.h" #include "ppapi/native_client/src/trusted/plugin/utility.h" diff --git a/ppapi/native_client/src/trusted/plugin/pnacl_translate_thread.cc b/ppapi/native_client/src/trusted/plugin/pnacl_translate_thread.cc index 947bf1c7..10f01bb 100644 --- a/ppapi/native_client/src/trusted/plugin/pnacl_translate_thread.cc +++ b/ppapi/native_client/src/trusted/plugin/pnacl_translate_thread.cc @@ -39,7 +39,7 @@ PnaclTranslateThread::PnaclTranslateThread() : llc_subprocess_active_(false), ld_subprocess_active_(false), done_(false), compile_time_(0), - manifest_id_(0), + manifest_(NULL), obj_files_(NULL), nexe_file_(NULL), coordinator_error_info_(NULL), @@ -53,7 +53,7 @@ PnaclTranslateThread::PnaclTranslateThread() : llc_subprocess_active_(false), void PnaclTranslateThread::RunTranslate( const pp::CompletionCallback& finish_callback, - int32_t manifest_id, + const Manifest* manifest, const std::vector<TempFile*>* obj_files, TempFile* nexe_file, nacl::DescWrapper* invalid_desc_wrapper, @@ -63,7 +63,7 @@ void PnaclTranslateThread::RunTranslate( PnaclCoordinator* coordinator, Plugin* plugin) { PLUGIN_PRINTF(("PnaclStreamingTranslateThread::RunTranslate)\n")); - manifest_id_ = manifest_id; + manifest_ = manifest; obj_files_ = obj_files; nexe_file_ = nexe_file; invalid_desc_wrapper_ = invalid_desc_wrapper; @@ -129,7 +129,7 @@ void PnaclTranslateThread::PutBytes(std::vector<char>* bytes, NaClSubprocess* PnaclTranslateThread::StartSubprocess( const nacl::string& url_for_nexe, - int32_t manifest_id, + const Manifest* manifest, ErrorInfo* error_info) { PLUGIN_PRINTF(("PnaclTranslateThread::StartSubprocess (url_for_nexe=%s)\n", url_for_nexe.c_str())); @@ -140,8 +140,8 @@ NaClSubprocess* PnaclTranslateThread::StartSubprocess( // string gets silently dropped by GURL. nacl::string full_url = resources_->GetFullUrl( url_for_nexe, plugin_->nacl_interface()->GetSandboxArch()); - nacl::scoped_ptr<NaClSubprocess> subprocess(plugin_->LoadHelperNaClModule( - full_url, wrapper, manifest_id, error_info)); + nacl::scoped_ptr<NaClSubprocess> subprocess( + plugin_->LoadHelperNaClModule(full_url, wrapper, manifest, error_info)); if (subprocess.get() == NULL) { PLUGIN_PRINTF(( "PnaclTranslateThread::StartSubprocess: subprocess creation failed\n")); @@ -173,7 +173,7 @@ void PnaclTranslateThread::DoTranslate() { nacl::MutexLocker ml(&subprocess_mu_); int64_t llc_start_time = NaClGetTimeOfDayMicroseconds(); llc_subprocess_.reset( - StartSubprocess(resources_->GetLlcUrl(), manifest_id_, &error_info)); + StartSubprocess(resources_->GetLlcUrl(), manifest_, &error_info)); if (llc_subprocess_ == NULL) { TranslateFailed(PP_NACL_ERROR_PNACL_LLC_SETUP, "Compile process could not be created: " + @@ -350,7 +350,7 @@ bool PnaclTranslateThread::RunLdSubprocess() { nacl::MutexLocker ml(&subprocess_mu_); int64_t ld_start_time = NaClGetTimeOfDayMicroseconds(); ld_subprocess_.reset( - StartSubprocess(resources_->GetLdUrl(), manifest_id_, &error_info)); + StartSubprocess(resources_->GetLdUrl(), manifest_, &error_info)); if (ld_subprocess_ == NULL) { TranslateFailed(PP_NACL_ERROR_PNACL_LD_SETUP, "Link process could not be created: " + diff --git a/ppapi/native_client/src/trusted/plugin/pnacl_translate_thread.h b/ppapi/native_client/src/trusted/plugin/pnacl_translate_thread.h index 84ce392..db1dbf0 100644 --- a/ppapi/native_client/src/trusted/plugin/pnacl_translate_thread.h +++ b/ppapi/native_client/src/trusted/plugin/pnacl_translate_thread.h @@ -28,6 +28,7 @@ class DescWrapper; namespace plugin { +class Manifest; class NaClSubprocess; class Plugin; class PnaclCoordinator; @@ -42,7 +43,7 @@ class PnaclTranslateThread { // Start the translation process. It will continue to run and consume data // as it is passed in with PutBytes. void RunTranslate(const pp::CompletionCallback& finish_callback, - int32_t manifest_id, + const Manifest* manifest, const std::vector<TempFile*>* obj_files, TempFile* nexe_file, nacl::DescWrapper* invalid_desc_wrapper, @@ -68,7 +69,7 @@ class PnaclTranslateThread { private: // Starts an individual llc or ld subprocess used for translation. NaClSubprocess* StartSubprocess(const nacl::string& url, - int32_t manifest_id, + const Manifest* manifest, ErrorInfo* error_info); // Helper thread entry point for translation. Takes a pointer to // PnaclTranslateThread and calls DoTranslate(). @@ -113,7 +114,7 @@ class PnaclTranslateThread { int64_t compile_time_; // Data about the translation files, owned by the coordinator - int32_t manifest_id_; + const Manifest* manifest_; const std::vector<TempFile*>* obj_files_; TempFile* nexe_file_; nacl::DescWrapper* invalid_desc_wrapper_; diff --git a/ppapi/native_client/src/trusted/plugin/service_runtime.cc b/ppapi/native_client/src/trusted/plugin/service_runtime.cc index c3a7f94..d7c8683 100644 --- a/ppapi/native_client/src/trusted/plugin/service_runtime.cc +++ b/ppapi/native_client/src/trusted/plugin/service_runtime.cc @@ -47,6 +47,7 @@ #include "ppapi/cpp/core.h" #include "ppapi/cpp/completion_callback.h" +#include "ppapi/native_client/src/trusted/plugin/manifest.h" #include "ppapi/native_client/src/trusted/plugin/plugin.h" #include "ppapi/native_client/src/trusted/plugin/plugin_error.h" #include "ppapi/native_client/src/trusted/plugin/pnacl_resources.h" @@ -197,13 +198,13 @@ void OpenManifestEntryResource::MaybeRunCallback(int32_t pp_error) { PluginReverseInterface::PluginReverseInterface( nacl::WeakRefAnchor* anchor, Plugin* plugin, - int32_t manifest_id, + const Manifest* manifest, ServiceRuntime* service_runtime, pp::CompletionCallback init_done_cb, pp::CompletionCallback crash_cb) : anchor_(anchor), plugin_(plugin), - manifest_id_(manifest_id), + manifest_(manifest), service_runtime_(service_runtime), shutting_down_(false), init_done_cb_(init_done_cb), @@ -346,13 +347,9 @@ void PluginReverseInterface::OpenManifestEntry_MainThreadContinuation( NaClLog(4, "Entered OpenManifestEntry_MainThreadContinuation\n"); - PP_Var pp_mapped_url; + std::string mapped_url; PP_PNaClOptions pnacl_options = {PP_FALSE, PP_FALSE, 2}; - if (!GetNaClInterface()->ManifestResolveKey(plugin_->pp_instance(), - manifest_id_, - p->url.c_str(), - &pp_mapped_url, - &pnacl_options)) { + if (!manifest_->ResolveKey(p->url, &mapped_url, &pnacl_options)) { NaClLog(4, "OpenManifestEntry_MainThreadContinuation: ResolveKey failed\n"); // Failed, and error_info has the details on what happened. Wake // up requesting thread -- we are done. @@ -365,7 +362,6 @@ void PluginReverseInterface::OpenManifestEntry_MainThreadContinuation( p->MaybeRunCallback(PP_OK); return; } - nacl::string mapped_url = pp::Var(pp_mapped_url).AsString(); NaClLog(4, "OpenManifestEntry_MainThreadContinuation: " "ResolveKey: %s -> %s (pnacl_translate(%d))\n", @@ -564,7 +560,7 @@ void PluginReverseInterface::AddTempQuotaManagedFile( } ServiceRuntime::ServiceRuntime(Plugin* plugin, - int32_t manifest_id, + const Manifest* manifest, bool main_service_runtime, bool uses_nonsfi_mode, pp::CompletionCallback init_done_cb, @@ -575,7 +571,7 @@ ServiceRuntime::ServiceRuntime(Plugin* plugin, reverse_service_(NULL), anchor_(new nacl::WeakRefAnchor()), rev_interface_(new PluginReverseInterface(anchor_, plugin, - manifest_id, + manifest, this, init_done_cb, crash_cb)), exit_status_(-1), diff --git a/ppapi/native_client/src/trusted/plugin/service_runtime.h b/ppapi/native_client/src/trusted/plugin/service_runtime.h index 74dc68d..ca12764 100644 --- a/ppapi/native_client/src/trusted/plugin/service_runtime.h +++ b/ppapi/native_client/src/trusted/plugin/service_runtime.h @@ -40,6 +40,7 @@ class FileIO; namespace plugin { class ErrorInfo; +class Manifest; class OpenManifestEntryAsyncCallback; class Plugin; class SrpcClient; @@ -146,7 +147,7 @@ class PluginReverseInterface: public nacl::ReverseInterface { public: PluginReverseInterface(nacl::WeakRefAnchor* anchor, Plugin* plugin, - int32_t manifest_id, + const Manifest* manifest, ServiceRuntime* service_runtime, pp::CompletionCallback init_done_cb, pp::CompletionCallback crash_cb); @@ -205,7 +206,7 @@ class PluginReverseInterface: public nacl::ReverseInterface { nacl::WeakRefAnchor* anchor_; // holds a ref Plugin* plugin_; // value may be copied, but should be used only in // main thread in WeakRef-protected callbacks. - int32_t manifest_id_; + const Manifest* manifest_; ServiceRuntime* service_runtime_; NaClMutex mu_; NaClCondVar cv_; @@ -222,7 +223,7 @@ class ServiceRuntime { // TODO(sehr): This class should also implement factory methods, using the // Start method below. ServiceRuntime(Plugin* plugin, - int32_t manifest_id, + const Manifest* manifest, bool main_service_runtime, bool uses_nonsfi_mode, pp::CompletionCallback init_done_cb, diff --git a/ppapi/native_client/src/untrusted/pnacl_irt_shim/pnacl_shim.c b/ppapi/native_client/src/untrusted/pnacl_irt_shim/pnacl_shim.c index 7005c05..4713148 100644 --- a/ppapi/native_client/src/untrusted/pnacl_irt_shim/pnacl_shim.c +++ b/ppapi/native_client/src/untrusted/pnacl_irt_shim/pnacl_shim.c @@ -3281,31 +3281,6 @@ static void Pnacl_M25_PPB_NaCl_Private_DownloadManifestToBuffer(PP_Instance inst iface->DownloadManifestToBuffer(instance, data, *callback); } -static int32_t Pnacl_M25_PPB_NaCl_Private_CreatePnaclManifest(PP_Instance instance) { - const struct PPB_NaCl_Private_1_0 *iface = Pnacl_WrapperInfo_PPB_NaCl_Private_1_0.real_iface; - return iface->CreatePnaclManifest(instance); -} - -static int32_t Pnacl_M25_PPB_NaCl_Private_CreateJsonManifest(PP_Instance instance, const char* manifest_base_url, const char* sandbox_isa, const char* manifest_data) { - const struct PPB_NaCl_Private_1_0 *iface = Pnacl_WrapperInfo_PPB_NaCl_Private_1_0.real_iface; - return iface->CreateJsonManifest(instance, manifest_base_url, sandbox_isa, manifest_data); -} - -static void Pnacl_M25_PPB_NaCl_Private_DestroyManifest(PP_Instance instance, int32_t manifest_id) { - const struct PPB_NaCl_Private_1_0 *iface = Pnacl_WrapperInfo_PPB_NaCl_Private_1_0.real_iface; - iface->DestroyManifest(instance, manifest_id); -} - -static PP_Bool Pnacl_M25_PPB_NaCl_Private_GetManifestProgramURL(PP_Instance instance, int32_t manifest_id, struct PP_Var* full_url, struct PP_PNaClOptions* pnacl_options, PP_Bool* uses_nonsfi_mode) { - const struct PPB_NaCl_Private_1_0 *iface = Pnacl_WrapperInfo_PPB_NaCl_Private_1_0.real_iface; - return iface->GetManifestProgramURL(instance, manifest_id, full_url, pnacl_options, uses_nonsfi_mode); -} - -static PP_Bool Pnacl_M25_PPB_NaCl_Private_ManifestResolveKey(PP_Instance instance, int32_t manifest_id, const char* key, struct PP_Var* full_url, struct PP_PNaClOptions* pnacl_options) { - const struct PPB_NaCl_Private_1_0 *iface = Pnacl_WrapperInfo_PPB_NaCl_Private_1_0.real_iface; - return iface->ManifestResolveKey(instance, manifest_id, key, full_url, pnacl_options); -} - /* End wrapper methods for PPB_NaCl_Private_1_0 */ /* Begin wrapper methods for PPB_NetAddress_Private_0_1 */ @@ -5037,12 +5012,7 @@ static const struct PPB_NaCl_Private_1_0 Pnacl_Wrappers_PPB_NaCl_Private_1_0 = { .GetManifestURLArgument = (struct PP_Var (*)(PP_Instance instance))&Pnacl_M25_PPB_NaCl_Private_GetManifestURLArgument, .IsPNaCl = (PP_Bool (*)(PP_Instance instance))&Pnacl_M25_PPB_NaCl_Private_IsPNaCl, .DevInterfacesEnabled = (PP_Bool (*)(PP_Instance instance))&Pnacl_M25_PPB_NaCl_Private_DevInterfacesEnabled, - .DownloadManifestToBuffer = (void (*)(PP_Instance instance, struct PP_Var* data, struct PP_CompletionCallback callback))&Pnacl_M25_PPB_NaCl_Private_DownloadManifestToBuffer, - .CreatePnaclManifest = (int32_t (*)(PP_Instance instance))&Pnacl_M25_PPB_NaCl_Private_CreatePnaclManifest, - .CreateJsonManifest = (int32_t (*)(PP_Instance instance, const char* manifest_base_url, const char* sandbox_isa, const char* manifest_data))&Pnacl_M25_PPB_NaCl_Private_CreateJsonManifest, - .DestroyManifest = (void (*)(PP_Instance instance, int32_t manifest_id))&Pnacl_M25_PPB_NaCl_Private_DestroyManifest, - .GetManifestProgramURL = (PP_Bool (*)(PP_Instance instance, int32_t manifest_id, struct PP_Var* full_url, struct PP_PNaClOptions* pnacl_options, PP_Bool* uses_nonsfi_mode))&Pnacl_M25_PPB_NaCl_Private_GetManifestProgramURL, - .ManifestResolveKey = (PP_Bool (*)(PP_Instance instance, int32_t manifest_id, const char* key, struct PP_Var* full_url, struct PP_PNaClOptions* pnacl_options))&Pnacl_M25_PPB_NaCl_Private_ManifestResolveKey + .DownloadManifestToBuffer = (void (*)(PP_Instance instance, struct PP_Var* data, struct PP_CompletionCallback callback))&Pnacl_M25_PPB_NaCl_Private_DownloadManifestToBuffer }; static const struct PPB_NetAddress_Private_0_1 Pnacl_Wrappers_PPB_NetAddress_Private_0_1 = { |