summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoryusukes <yusukes@chromium.org>2015-03-10 11:51:45 -0700
committerCommit bot <commit-bot@chromium.org>2015-03-10 18:52:23 +0000
commit67e8acdac9e043dd710058ef2e01ca7ad2b29825 (patch)
treeb5d78e0812e8be26779a803bfc53fa69b986e969
parentefe950c2db75b0cfd043e068a4cfc68ab393dac4 (diff)
downloadchromium_src-67e8acdac9e043dd710058ef2e01ca7ad2b29825.zip
chromium_src-67e8acdac9e043dd710058ef2e01ca7ad2b29825.tar.gz
chromium_src-67e8acdac9e043dd710058ef2e01ca7ad2b29825.tar.bz2
Non-SFI NaCl: Batch-open resource files
* Let the renderer pass URLs and manifest keys of the resource files when it asks the browser to start a new plugin process. * The browser opens all the URLs and passes file handlers to the plugin process if the process is for non-SFI mode. * Modify the non-SFI loader so that it can return a pre-opened handle without doing a renderer IPC when open_resource IRT is called. This CL does not change the current behavior of SFI NaCl. SFI NaCl support will be added in a separate CL: https://codereview.chromium.org/728113002/ Note that this CL is primarily for ARC (App Runtime for Chrome) which has 70+ DSO files. With this CL, the loading time of arc.nexe gets ~40% shorter. This CL should not affect NaCl applications other than ARC because most of them do not have that many DSO files, and even if they have some, opening one DSO file in the browser process takes only about 0.4ms (on Z620) which is usually negligible. TEST=PackagedAppTest.SuccessfulLoad TEST=manually checked that SFI-NaCl and PNaCl are still working. BUG=nativeclient:3802 BUG=348232 Review URL: https://codereview.chromium.org/649603004 Cr-Commit-Position: refs/heads/master@{#319931}
-rw-r--r--components/nacl/browser/nacl_host_message_filter.cc107
-rw-r--r--components/nacl/browser/nacl_host_message_filter.h14
-rw-r--r--components/nacl/browser/nacl_process_host.cc90
-rw-r--r--components/nacl/browser/nacl_process_host.h27
-rw-r--r--components/nacl/common/nacl_host_messages.h1
-rw-r--r--components/nacl/common/nacl_messages.h7
-rw-r--r--components/nacl/common/nacl_types.cc17
-rw-r--r--components/nacl/common/nacl_types.h37
-rw-r--r--components/nacl/loader/nacl_listener.cc2
-rw-r--r--components/nacl/loader/nonsfi/nonsfi_listener.cc11
-rw-r--r--components/nacl/renderer/json_manifest.cc18
-rw-r--r--components/nacl/renderer/json_manifest.h6
-rw-r--r--components/nacl/renderer/ppb_nacl_private_impl.cc54
-rw-r--r--ppapi/nacl_irt/irt_manifest.h8
-rw-r--r--ppapi/nacl_irt/manifest_service.cc38
15 files changed, 368 insertions, 69 deletions
diff --git a/components/nacl/browser/nacl_host_message_filter.cc b/components/nacl/browser/nacl_host_message_filter.cc
index 3726a7e..18a695e 100644
--- a/components/nacl/browser/nacl_host_message_filter.cc
+++ b/components/nacl/browser/nacl_host_message_filter.cc
@@ -24,6 +24,11 @@ namespace nacl {
namespace {
+// The maximum number of resource file handles NaClProcessMsg_Start message
+// can have.
+// TODO(yusukes): Increase the number.
+const size_t kMaxPreOpenResourceFiles = 2;
+
ppapi::PpapiPermissions GetNaClPermissions(
uint32 permission_bits,
content::BrowserContext* browser_context,
@@ -122,19 +127,16 @@ void NaClHostMessageFilter::OnLaunchNaCl(
// of the whitelisting parameters anyway.
if (launch_params.process_type == kPNaClTranslatorProcessType) {
uint32 perms = launch_params.permission_bits & ppapi::PERMISSION_DEV;
- LaunchNaClContinuation(
+ LaunchNaClContinuationOnIOThread(
launch_params,
reply_msg,
+ std::vector<nacl::NaClResourceFileInfo>(),
ppapi::PpapiPermissions(perms));
return;
}
- content::BrowserThread::PostTaskAndReplyWithResult(
+ content::BrowserThread::PostTask(
content::BrowserThread::UI,
FROM_HERE,
- base::Bind(&GetPpapiPermissions,
- launch_params.permission_bits,
- render_process_id_,
- launch_params.render_view_id),
base::Bind(&NaClHostMessageFilter::LaunchNaClContinuation,
this,
launch_params,
@@ -143,8 +145,100 @@ void NaClHostMessageFilter::OnLaunchNaCl(
void NaClHostMessageFilter::LaunchNaClContinuation(
const nacl::NaClLaunchParams& launch_params,
+ IPC::Message* reply_msg) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+ ppapi::PpapiPermissions permissions =
+ GetPpapiPermissions(launch_params.permission_bits,
+ render_process_id_,
+ launch_params.render_view_id);
+
+ content::RenderViewHost* rvh = content::RenderViewHost::FromID(
+ render_process_id(), launch_params.render_view_id);
+ if (!rvh) {
+ BadMessageReceived(); // Kill the renderer.
+ return;
+ }
+
+ nacl::NaClLaunchParams safe_launch_params(launch_params);
+ safe_launch_params.resource_files_to_prefetch.clear();
+
+ content::SiteInstance* site_instance = rvh->GetSiteInstance();
+ for (size_t i = 0; i < launch_params.resource_files_to_prefetch.size(); ++i) {
+ GURL gurl(launch_params.resource_files_to_prefetch[i].second);
+ // Important security check: Do the same check as OpenNaClExecutable()
+ // in nacl_file_host.cc.
+ if (!content::SiteInstance::IsSameWebSite(
+ site_instance->GetBrowserContext(),
+ site_instance->GetSiteURL(),
+ gurl)) {
+ continue;
+ }
+ safe_launch_params.resource_files_to_prefetch.push_back(
+ launch_params.resource_files_to_prefetch[i]);
+ }
+
+ // Process a list of resource file URLs in
+ // |launch_params.resource_files_to_prefetch|.
+ content::BrowserThread::PostBlockingPoolTask(
+ FROM_HERE,
+ base::Bind(&NaClHostMessageFilter::BatchOpenResourceFiles,
+ this,
+ safe_launch_params,
+ reply_msg,
+ permissions));
+}
+
+void NaClHostMessageFilter::BatchOpenResourceFiles(
+ const nacl::NaClLaunchParams& launch_params,
+ IPC::Message* reply_msg,
+ ppapi::PpapiPermissions permissions) {
+ std::vector<nacl::NaClResourceFileInfo> prefetched_resource_files_info;
+ for (size_t i = 0; i < launch_params.resource_files_to_prefetch.size(); ++i) {
+ nacl::NaClResourceFileInfo prefetched_resource_file;
+ GURL gurl(launch_params.resource_files_to_prefetch[i].second);
+ if (!nacl::NaClBrowser::GetDelegate()->MapUrlToLocalFilePath(
+ gurl,
+ true, // use_blocking_api
+ profile_directory_,
+ &prefetched_resource_file.file_path_metadata)) {
+ continue;
+ }
+ base::File file = nacl::OpenNaClReadExecImpl(
+ prefetched_resource_file.file_path_metadata,
+ true /* is_executable */);
+ if (!file.IsValid())
+ continue;
+
+ prefetched_resource_file.file =
+ IPC::TakeFileHandleForProcess(file.Pass(), PeerHandle());
+ prefetched_resource_file.file_key =
+ launch_params.resource_files_to_prefetch[i].first;
+
+ prefetched_resource_files_info.push_back(prefetched_resource_file);
+ if (prefetched_resource_files_info.size() >= kMaxPreOpenResourceFiles)
+ break;
+ }
+
+ content::BrowserThread::PostTask(
+ content::BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(&NaClHostMessageFilter::LaunchNaClContinuationOnIOThread,
+ this,
+ launch_params,
+ reply_msg,
+ prefetched_resource_files_info,
+ permissions));
+}
+
+void NaClHostMessageFilter::LaunchNaClContinuationOnIOThread(
+ const nacl::NaClLaunchParams& launch_params,
IPC::Message* reply_msg,
+ const std::vector<
+ nacl::NaClResourceFileInfo>& prefetched_resource_files_info,
ppapi::PpapiPermissions permissions) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+
NaClFileToken nexe_token = {
launch_params.nexe_token_lo, // lo
launch_params.nexe_token_hi // hi
@@ -179,6 +273,7 @@ void NaClHostMessageFilter::LaunchNaClContinuation(
GURL(launch_params.manifest_url),
base::File(nexe_file),
nexe_token,
+ prefetched_resource_files_info,
permissions,
launch_params.render_view_id,
launch_params.permission_bits,
diff --git a/components/nacl/browser/nacl_host_message_filter.h b/components/nacl/browser/nacl_host_message_filter.h
index 3c7f625..ec8ece4 100644
--- a/components/nacl/browser/nacl_host_message_filter.h
+++ b/components/nacl/browser/nacl_host_message_filter.h
@@ -5,6 +5,8 @@
#ifndef COMPONENTS_NACL_BROWSER_NACL_HOST_MESSAGE_FILTER_H_
#define COMPONENTS_NACL_BROWSER_NACL_HOST_MESSAGE_FILTER_H_
+#include <vector>
+
#include "base/files/file.h"
#include "base/files/file_path.h"
#include "base/memory/weak_ptr.h"
@@ -15,6 +17,7 @@ class GURL;
namespace nacl {
struct NaClLaunchParams;
+struct NaClResourceFileInfo;
struct PnaclCacheInfo;
}
@@ -51,9 +54,18 @@ class NaClHostMessageFilter : public content::BrowserMessageFilter {
void OnLaunchNaCl(const NaClLaunchParams& launch_params,
IPC::Message* reply_msg);
- void LaunchNaClContinuation(const nacl::NaClLaunchParams& launch_params,
+ void BatchOpenResourceFiles(const nacl::NaClLaunchParams& launch_params,
IPC::Message* reply_msg,
ppapi::PpapiPermissions permissions);
+ void LaunchNaClContinuation(
+ const nacl::NaClLaunchParams& launch_params,
+ IPC::Message* reply_msg);
+ void LaunchNaClContinuationOnIOThread(
+ const nacl::NaClLaunchParams& launch_params,
+ IPC::Message* reply_msg,
+ const std::vector<
+ nacl::NaClResourceFileInfo>& prefetched_resource_files_info,
+ ppapi::PpapiPermissions permissions);
void OnGetReadonlyPnaclFd(const std::string& filename,
bool is_executable,
IPC::Message* reply_msg);
diff --git a/components/nacl/browser/nacl_process_host.cc b/components/nacl/browser/nacl_process_host.cc
index e143416..a0c8e56 100644
--- a/components/nacl/browser/nacl_process_host.cc
+++ b/components/nacl/browser/nacl_process_host.cc
@@ -234,19 +234,23 @@ void CloseFile(base::File file) {
unsigned NaClProcessHost::keepalive_throttle_interval_milliseconds_ =
ppapi::kKeepaliveThrottleIntervalDefaultMilliseconds;
-NaClProcessHost::NaClProcessHost(const GURL& manifest_url,
- base::File nexe_file,
- const NaClFileToken& nexe_token,
- ppapi::PpapiPermissions permissions,
- int render_view_id,
- uint32 permission_bits,
- bool uses_nonsfi_mode,
- bool off_the_record,
- NaClAppProcessType process_type,
- const base::FilePath& profile_directory)
+NaClProcessHost::NaClProcessHost(
+ const GURL& manifest_url,
+ base::File nexe_file,
+ const NaClFileToken& nexe_token,
+ const std::vector<
+ nacl::NaClResourceFileInfo>& prefetched_resource_files_info,
+ ppapi::PpapiPermissions permissions,
+ int render_view_id,
+ uint32 permission_bits,
+ bool uses_nonsfi_mode,
+ bool off_the_record,
+ NaClAppProcessType process_type,
+ const base::FilePath& profile_directory)
: manifest_url_(manifest_url),
nexe_file_(nexe_file.Pass()),
nexe_token_(nexe_token),
+ prefetched_resource_files_info_(prefetched_resource_files_info),
permissions_(permissions),
#if defined(OS_WIN)
process_launched_by_broker_(false),
@@ -294,6 +298,16 @@ NaClProcessHost::~NaClProcessHost() {
NaClBrowser::GetInstance()->OnProcessEnd(process_->GetData().id);
}
+ for (size_t i = 0; i < prefetched_resource_files_info_.size(); ++i) {
+ // The process failed to launch for some reason. Close resource file
+ // handles.
+ base::File file(IPC::PlatformFileForTransitToFile(
+ prefetched_resource_files_info_[i].file));
+ content::BrowserThread::GetBlockingPool()->PostTask(
+ FROM_HERE,
+ base::Bind(&CloseFile, base::Passed(file.Pass())));
+ }
+
if (reply_msg_) {
// The process failed to launch for some reason.
// Don't keep the renderer hanging.
@@ -885,28 +899,42 @@ bool NaClProcessHost::StartNaClExecution() {
}
base::FilePath file_path;
- // Don't retrieve the file path when using nonsfi mode; there's no validation
- // caching in that case, so it's unnecessary work, and would expose the file
- // path to the plugin.
- if (!uses_nonsfi_mode_ &&
- NaClBrowser::GetInstance()->GetFilePath(nexe_token_.lo,
- nexe_token_.hi,
- &file_path)) {
- // We have to reopen the file in the browser process; we don't want a
- // compromised renderer to pass an arbitrary fd that could get loaded
- // into the plugin process.
- if (base::PostTaskAndReplyWithResult(
- content::BrowserThread::GetBlockingPool(),
- FROM_HERE,
- base::Bind(OpenNaClReadExecImpl,
- file_path,
- true /* is_executable */),
- base::Bind(&NaClProcessHost::StartNaClFileResolved,
- weak_factory_.GetWeakPtr(),
- params,
- file_path))) {
- return true;
+ if (uses_nonsfi_mode_) {
+ // Don't retrieve the file path when using nonsfi mode; there's no
+ // validation caching in that case, so it's unnecessary work, and would
+ // expose the file path to the plugin.
+
+ // Pass the pre-opened resource files to the loader. For the same reason
+ // as above, use an empty base::FilePath.
+ for (size_t i = 0; i < prefetched_resource_files_info_.size(); ++i) {
+ params.prefetched_resource_files.push_back(
+ NaClResourceFileInfo(prefetched_resource_files_info_[i].file,
+ base::FilePath(),
+ prefetched_resource_files_info_[i].file_key));
+ }
+ prefetched_resource_files_info_.clear();
+ } else {
+ if (NaClBrowser::GetInstance()->GetFilePath(nexe_token_.lo,
+ nexe_token_.hi,
+ &file_path)) {
+ // We have to reopen the file in the browser process; we don't want a
+ // compromised renderer to pass an arbitrary fd that could get loaded
+ // into the plugin process.
+ if (base::PostTaskAndReplyWithResult(
+ content::BrowserThread::GetBlockingPool(),
+ FROM_HERE,
+ base::Bind(OpenNaClReadExecImpl,
+ file_path,
+ true /* is_executable */),
+ base::Bind(&NaClProcessHost::StartNaClFileResolved,
+ weak_factory_.GetWeakPtr(),
+ params,
+ file_path))) {
+ return true;
+ }
}
+ // TODO(yusukes): Handle |prefetched_resource_files_info_| for SFI-NaCl.
+ DCHECK(prefetched_resource_files_info_.empty());
}
params.nexe_file = IPC::TakeFileHandleForProcess(nexe_file_.Pass(),
diff --git a/components/nacl/browser/nacl_process_host.h b/components/nacl/browser/nacl_process_host.h
index f7693ea..324db11 100644
--- a/components/nacl/browser/nacl_process_host.h
+++ b/components/nacl/browser/nacl_process_host.h
@@ -7,6 +7,8 @@
#include "build/build_config.h"
+#include <vector>
+
#include "base/files/file.h"
#include "base/files/file_path.h"
#include "base/files/file_util_proxy.h"
@@ -60,6 +62,7 @@ class NaClProcessHost : public content::BrowserChildProcessHostDelegate {
// executed.
// nexe_file: A file that corresponds to the nexe module to be loaded.
// nexe_token: A cache validation token for nexe_file.
+ // prefetched_resource_files_info: An array of resource files prefetched.
// permissions: PPAPI permissions, to control access to private APIs.
// render_view_id: RenderView routing id, to control access to private APIs.
// permission_bits: controls which interfaces the NaCl plugin can use.
@@ -67,16 +70,19 @@ class NaClProcessHost : public content::BrowserChildProcessHostDelegate {
// off_the_record: was the process launched from an incognito renderer?
// process_type: the type of NaCl process.
// profile_directory: is the path of current profile directory.
- NaClProcessHost(const GURL& manifest_url,
- base::File nexe_file,
- const NaClFileToken& nexe_token,
- ppapi::PpapiPermissions permissions,
- int render_view_id,
- uint32 permission_bits,
- bool uses_nonsfi_mode,
- bool off_the_record,
- NaClAppProcessType process_type,
- const base::FilePath& profile_directory);
+ NaClProcessHost(
+ const GURL& manifest_url,
+ base::File nexe_file,
+ const NaClFileToken& nexe_token,
+ const std::vector<
+ nacl::NaClResourceFileInfo>& prefetched_resource_files_info,
+ ppapi::PpapiPermissions permissions,
+ int render_view_id,
+ uint32 permission_bits,
+ bool uses_nonsfi_mode,
+ bool off_the_record,
+ NaClAppProcessType process_type,
+ const base::FilePath& profile_directory);
~NaClProcessHost() override;
void OnProcessCrashed(int exit_status) override;
@@ -192,6 +198,7 @@ class NaClProcessHost : public content::BrowserChildProcessHostDelegate {
GURL manifest_url_;
base::File nexe_file_;
NaClFileToken nexe_token_;
+ std::vector<nacl::NaClResourceFileInfo> prefetched_resource_files_info_;
ppapi::PpapiPermissions permissions_;
diff --git a/components/nacl/common/nacl_host_messages.h b/components/nacl/common/nacl_host_messages.h
index b57ff1d..21cdd6d 100644
--- a/components/nacl/common/nacl_host_messages.h
+++ b/components/nacl/common/nacl_host_messages.h
@@ -25,6 +25,7 @@ IPC_STRUCT_TRAITS_BEGIN(nacl::NaClLaunchParams)
IPC_STRUCT_TRAITS_MEMBER(nexe_file)
IPC_STRUCT_TRAITS_MEMBER(nexe_token_lo)
IPC_STRUCT_TRAITS_MEMBER(nexe_token_hi)
+ IPC_STRUCT_TRAITS_MEMBER(resource_files_to_prefetch)
IPC_STRUCT_TRAITS_MEMBER(render_view_id)
IPC_STRUCT_TRAITS_MEMBER(permission_bits)
IPC_STRUCT_TRAITS_MEMBER(uses_nonsfi_mode)
diff --git a/components/nacl/common/nacl_messages.h b/components/nacl/common/nacl_messages.h
index 51a73f8..191d5b9 100644
--- a/components/nacl/common/nacl_messages.h
+++ b/components/nacl/common/nacl_messages.h
@@ -17,6 +17,7 @@
IPC_STRUCT_TRAITS_BEGIN(nacl::NaClStartParams)
IPC_STRUCT_TRAITS_MEMBER(nexe_file)
IPC_STRUCT_TRAITS_MEMBER(nexe_file_path_metadata)
+ IPC_STRUCT_TRAITS_MEMBER(prefetched_resource_files)
IPC_STRUCT_TRAITS_MEMBER(handles)
IPC_STRUCT_TRAITS_MEMBER(debug_stub_server_bound_socket)
IPC_STRUCT_TRAITS_MEMBER(validation_cache_enabled)
@@ -29,6 +30,12 @@ IPC_STRUCT_TRAITS_BEGIN(nacl::NaClStartParams)
IPC_STRUCT_TRAITS_MEMBER(crash_info_shmem_handle)
IPC_STRUCT_TRAITS_END()
+IPC_STRUCT_TRAITS_BEGIN(nacl::NaClResourceFileInfo)
+ IPC_STRUCT_TRAITS_MEMBER(file)
+ IPC_STRUCT_TRAITS_MEMBER(file_path_metadata)
+ IPC_STRUCT_TRAITS_MEMBER(file_key)
+IPC_STRUCT_TRAITS_END()
+
//-----------------------------------------------------------------------------
// NaClProcess messages
// These are messages sent between the browser and the NaCl process.
diff --git a/components/nacl/common/nacl_types.cc b/components/nacl/common/nacl_types.cc
index fec4a02..4abb828 100644
--- a/components/nacl/common/nacl_types.cc
+++ b/components/nacl/common/nacl_types.cc
@@ -20,6 +20,20 @@ NaClStartParams::NaClStartParams()
NaClStartParams::~NaClStartParams() {
}
+NaClResourceFileInfo::NaClResourceFileInfo()
+ : file(IPC::InvalidPlatformFileForTransit()) {
+}
+
+NaClResourceFileInfo::NaClResourceFileInfo(
+ IPC::PlatformFileForTransit file,
+ const base::FilePath& file_path_metadata,
+ const std::string& file_key)
+ : file(file), file_path_metadata(file_path_metadata), file_key(file_key) {
+}
+
+NaClResourceFileInfo::~NaClResourceFileInfo() {
+}
+
NaClLaunchParams::NaClLaunchParams()
: nexe_file(IPC::InvalidPlatformFileForTransit()),
nexe_token_lo(0),
@@ -34,6 +48,8 @@ NaClLaunchParams::NaClLaunchParams(
const IPC::PlatformFileForTransit& nexe_file,
uint64_t nexe_token_lo,
uint64_t nexe_token_hi,
+ const std::vector<
+ std::pair<std::string, std::string> >& resource_files_to_prefetch,
int render_view_id,
uint32 permission_bits,
bool uses_nonsfi_mode,
@@ -42,6 +58,7 @@ NaClLaunchParams::NaClLaunchParams(
nexe_file(nexe_file),
nexe_token_lo(nexe_token_lo),
nexe_token_hi(nexe_token_hi),
+ resource_files_to_prefetch(resource_files_to_prefetch),
render_view_id(render_view_id),
permission_bits(permission_bits),
uses_nonsfi_mode(uses_nonsfi_mode),
diff --git a/components/nacl/common/nacl_types.h b/components/nacl/common/nacl_types.h
index 11aaeb9..f691edf 100644
--- a/components/nacl/common/nacl_types.h
+++ b/components/nacl/common/nacl_types.h
@@ -6,6 +6,7 @@
#define COMPONENTS_NACL_COMMON_NACL_TYPES_H_
#include <string>
+#include <utility>
#include <vector>
#include "base/basictypes.h"
@@ -57,6 +58,20 @@ enum NaClAppProcessType {
kNumNaClProcessTypes
};
+// Represents a single prefetched file that's listed in the "files" section of
+// a NaCl manifest file.
+struct NaClResourceFileInfo {
+ NaClResourceFileInfo();
+ NaClResourceFileInfo(IPC::PlatformFileForTransit file,
+ const base::FilePath& file_path,
+ const std::string& file_key);
+ ~NaClResourceFileInfo();
+
+ IPC::PlatformFileForTransit file;
+ base::FilePath file_path_metadata; // a key for validation caching
+ std::string file_key; // a key for open_resource
+};
+
// Parameters sent to the NaCl process when we start it.
struct NaClStartParams {
NaClStartParams();
@@ -66,6 +81,7 @@ struct NaClStartParams {
// Used only as a key for validation caching.
base::FilePath nexe_file_path_metadata;
+ std::vector<NaClResourceFileInfo> prefetched_resource_files;
std::vector<FileDescriptor> handles;
FileDescriptor debug_stub_server_bound_socket;
@@ -98,14 +114,18 @@ struct NaClStartParams {
// nacl_host_messages.h.
struct NaClLaunchParams {
NaClLaunchParams();
- NaClLaunchParams(const std::string& manifest_url,
- const IPC::PlatformFileForTransit& nexe_file,
- uint64_t nexe_token_lo,
- uint64_t nexe_token_hi,
- int render_view_id,
- uint32 permission_bits,
- bool uses_nonsfi_mode,
- NaClAppProcessType process_type);
+ NaClLaunchParams(
+ const std::string& manifest_url,
+ const IPC::PlatformFileForTransit& nexe_file,
+ uint64_t nexe_token_lo,
+ uint64_t nexe_token_hi,
+ // A pair of a manifest key and its resource URL.
+ const std::vector<
+ std::pair<std::string, std::string> >& resource_files_to_prefetch,
+ int render_view_id,
+ uint32 permission_bits,
+ bool uses_nonsfi_mode,
+ NaClAppProcessType process_type);
~NaClLaunchParams();
std::string manifest_url;
@@ -115,6 +135,7 @@ struct NaClLaunchParams {
IPC::PlatformFileForTransit nexe_file;
uint64_t nexe_token_lo;
uint64_t nexe_token_hi;
+ std::vector<std::pair<std::string, std::string> > resource_files_to_prefetch;
int render_view_id;
uint32 permission_bits;
diff --git a/components/nacl/loader/nacl_listener.cc b/components/nacl/loader/nacl_listener.cc
index 4d14f42..424112e 100644
--- a/components/nacl/loader/nacl_listener.cc
+++ b/components/nacl/loader/nacl_listener.cc
@@ -448,6 +448,8 @@ void NaClListener::OnStart(const nacl::NaClStartParams& params) {
#else
InjectDisabledMojo(nap);
#endif
+ // TODO(yusukes): Support pre-opening resource files.
+ CHECK(params.prefetched_resource_files.empty());
int exit_status;
if (!NaClChromeMainStart(nap, args, &exit_status))
diff --git a/components/nacl/loader/nonsfi/nonsfi_listener.cc b/components/nacl/loader/nonsfi/nonsfi_listener.cc
index d0d51f1..5f212ba 100644
--- a/components/nacl/loader/nonsfi/nonsfi_listener.cc
+++ b/components/nacl/loader/nonsfi/nonsfi_listener.cc
@@ -18,6 +18,7 @@
#include "ipc/ipc_channel_handle.h"
#include "ipc/ipc_switches.h"
#include "ipc/ipc_sync_channel.h"
+#include "ppapi/nacl_irt/irt_manifest.h"
#include "ppapi/nacl_irt/plugin_startup.h"
#if defined(OS_NACL_NONSFI)
@@ -156,6 +157,16 @@ void NonSfiListener::OnStart(const nacl::NaClStartParams& params) {
CHECK(params.nexe_file != IPC::InvalidPlatformFileForTransit());
CHECK(params.nexe_file_path_metadata.empty());
+ std::map<std::string, int>* key_fd_map = new std::map<std::string, int>;
+ for (size_t i = 0; i < params.prefetched_resource_files.size(); ++i) {
+ CHECK(params.prefetched_resource_files[i].file_path_metadata.empty());
+ key_fd_map->insert(std::make_pair(
+ params.prefetched_resource_files[i].file_key,
+ IPC::PlatformFileForTransitToPlatformFile(
+ params.prefetched_resource_files[i].file)));
+ }
+ ppapi::RegisterPreopenedDescriptorsNonSfi(key_fd_map);
+
MainStart(IPC::PlatformFileForTransitToPlatformFile(params.nexe_file));
}
diff --git a/components/nacl/renderer/json_manifest.cc b/components/nacl/renderer/json_manifest.cc
index 9518946..15425a5 100644
--- a/components/nacl/renderer/json_manifest.cc
+++ b/components/nacl/renderer/json_manifest.cc
@@ -442,6 +442,24 @@ bool JsonManifest::GetProgramURL(std::string* full_url,
return true;
}
+void JsonManifest::GetPrefetchableFiles(
+ std::vector<std::pair<std::string, std::string> >* out_files) const {
+ const Json::Value& files = dictionary_[kFilesKey];
+ if (!files.isObject())
+ return;
+
+ Json::Value::Members keys = files.getMemberNames();
+ for (size_t i = 0; i < keys.size(); ++i) {
+ std::string full_url;
+ PP_PNaClOptions unused_pnacl_options; // pnacl does not support "files".
+ // We skip invalid entries in "files".
+ if (GetKeyUrl(files, keys[i], &full_url, &unused_pnacl_options)) {
+ if (GURL(full_url).SchemeIs("chrome-extension"))
+ out_files->push_back(std::make_pair(keys[i], full_url));
+ }
+ }
+}
+
bool JsonManifest::ResolveKey(const std::string& key,
std::string* full_url,
PP_PNaClOptions* pnacl_options) const {
diff --git a/components/nacl/renderer/json_manifest.h b/components/nacl/renderer/json_manifest.h
index dbe54d5a..4117966 100644
--- a/components/nacl/renderer/json_manifest.h
+++ b/components/nacl/renderer/json_manifest.h
@@ -7,6 +7,7 @@
#include <set>
#include <string>
+#include <utility>
#include "components/nacl/renderer/ppb_nacl_private.h"
#include "ppapi/c/pp_array_output.h"
@@ -39,6 +40,11 @@ class JsonManifest {
bool* uses_nonsfi_mode,
ErrorInfo* error_info) const;
+ // Gets all the keys and their URLs in the "files" section that are
+ // prefetchable.
+ void GetPrefetchableFiles(
+ std::vector<std::pair<std::string, std::string> >* out_files) 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).
diff --git a/components/nacl/renderer/ppb_nacl_private_impl.cc b/components/nacl/renderer/ppb_nacl_private_impl.cc
index 3c84afe..fb5e6dc 100644
--- a/components/nacl/renderer/ppb_nacl_private_impl.cc
+++ b/components/nacl/renderer/ppb_nacl_private_impl.cc
@@ -89,6 +89,21 @@ bool InitializePnaclResourceHost() {
return true;
}
+bool CanOpenViaFastPath(content::PepperPluginInstance* plugin_instance,
+ const GURL& gurl) {
+ // Fast path only works for installed file URLs.
+ if (!gurl.SchemeIs("chrome-extension"))
+ return PP_kInvalidFileHandle;
+
+ // 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.
+ blink::WebSecurityOrigin security_origin =
+ plugin_instance->GetContainer()->element().document().securityOrigin();
+ return security_origin.canRequest(gurl);
+}
+
// This contains state that is produced by LaunchSelLdr() and consumed
// by StartPpapiProxy().
struct InstanceInfo {
@@ -375,7 +390,10 @@ void LaunchSelLdr(PP_Instance instance,
int routing_id = GetRoutingID(instance);
NexeLoadManager* load_manager = GetNexeLoadManager(instance);
DCHECK(load_manager);
- if (!routing_id || !load_manager) {
+ content::PepperPluginInstance* plugin_instance =
+ content::PepperPluginInstance::Get(instance);
+ DCHECK(plugin_instance);
+ if (!routing_id || !load_manager || !plugin_instance) {
if (nexe_file_info->handle != PP_kInvalidFileHandle) {
base::File closer(nexe_file_info->handle);
}
@@ -401,6 +419,23 @@ void LaunchSelLdr(PP_Instance instance,
IPC::PlatformFileForTransit nexe_for_transit =
IPC::InvalidPlatformFileForTransit();
+
+ std::vector<std::pair<
+ std::string /*key*/, std::string /*url*/> > resource_files_to_prefetch;
+ if (process_type == kNativeNaClProcessType && uses_nonsfi_mode) {
+ JsonManifest* manifest = GetJsonManifest(instance);
+ if (manifest)
+ manifest->GetPrefetchableFiles(&resource_files_to_prefetch);
+ for (size_t i = 0; i < resource_files_to_prefetch.size(); ++i) {
+ const GURL gurl(resource_files_to_prefetch[i].second);
+ // Important security check. Do not remove.
+ if (!CanOpenViaFastPath(plugin_instance, gurl)) {
+ resource_files_to_prefetch.clear();
+ break;
+ }
+ }
+ }
+
#if defined(OS_POSIX)
if (nexe_file_info->handle != PP_kInvalidFileHandle)
nexe_for_transit = base::FileDescriptor(nexe_file_info->handle, true);
@@ -418,6 +453,7 @@ void LaunchSelLdr(PP_Instance instance,
nexe_for_transit,
nexe_file_info->token_lo,
nexe_file_info->token_hi,
+ resource_files_to_prefetch,
routing_id,
perm_bits,
PP_ToBool(uses_nonsfi_mode),
@@ -711,11 +747,6 @@ PP_FileHandle OpenNaClExecutable(PP_Instance instance,
const char* file_url,
uint64_t* nonce_lo,
uint64_t* nonce_hi) {
- // Fast path only works for installed file URLs.
- GURL gurl(file_url);
- if (!gurl.SchemeIs("chrome-extension"))
- return PP_kInvalidFileHandle;
-
NexeLoadManager* load_manager = GetNexeLoadManager(instance);
DCHECK(load_manager);
if (!load_manager)
@@ -725,13 +756,10 @@ PP_FileHandle OpenNaClExecutable(PP_Instance instance,
content::PepperPluginInstance::Get(instance);
if (!plugin_instance)
return PP_kInvalidFileHandle;
- // 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.
- blink::WebSecurityOrigin security_origin =
- plugin_instance->GetContainer()->element().document().securityOrigin();
- if (!security_origin.canRequest(gurl))
+
+ GURL gurl(file_url);
+ // Important security check. Do not remove.
+ if (!CanOpenViaFastPath(plugin_instance, gurl))
return PP_kInvalidFileHandle;
IPC::PlatformFileForTransit out_fd = IPC::InvalidPlatformFileForTransit();
diff --git a/ppapi/nacl_irt/irt_manifest.h b/ppapi/nacl_irt/irt_manifest.h
index b1e0923..5938a45 100644
--- a/ppapi/nacl_irt/irt_manifest.h
+++ b/ppapi/nacl_irt/irt_manifest.h
@@ -5,6 +5,9 @@
#ifndef PPAPI_NACL_IRT_IRT_MANIFEST_H_
#define PPAPI_NACL_IRT_IRT_MANIFEST_H_
+#include <map>
+#include <string>
+
#include "ppapi/proxy/ppapi_proxy_export.h"
namespace ppapi {
@@ -16,6 +19,11 @@ namespace ppapi {
// on failure. See also irt_open_resource()'s comment.
PPAPI_PROXY_EXPORT int IrtOpenResource(const char* file, int* fd);
+#if !defined(OS_NACL_SFI)
+PPAPI_PROXY_EXPORT void RegisterPreopenedDescriptorsNonSfi(
+ std::map<std::string, int>* key_fd_map);
+#endif
+
} // namespace ppapi
#endif // PPAPI_NACL_IRT_IRT_MANIFEST_H_
diff --git a/ppapi/nacl_irt/manifest_service.cc b/ppapi/nacl_irt/manifest_service.cc
index 8e671b9..3c537b3 100644
--- a/ppapi/nacl_irt/manifest_service.cc
+++ b/ppapi/nacl_irt/manifest_service.cc
@@ -13,6 +13,12 @@
#include "ppapi/nacl_irt/plugin_startup.h"
#include "ppapi/proxy/ppapi_messages.h"
+#if !defined(OS_NACL_SFI)
+#include <pthread.h>
+#include <map>
+#include <string>
+#endif
+
namespace ppapi {
const char kFilePrefix[] = "files/";
@@ -120,11 +126,43 @@ bool ManifestService::OpenResource(const char* file, int* fd) {
return true;
}
+#if !defined(OS_NACL_SFI)
+namespace {
+
+pthread_mutex_t g_mu = PTHREAD_MUTEX_INITIALIZER;
+std::map<std::string, int>* g_prefetched_fds;
+
+} // namespace
+
+void RegisterPreopenedDescriptorsNonSfi(
+ std::map<std::string, int>* key_fd_map) {
+ pthread_mutex_lock(&g_mu);
+ DCHECK(!g_prefetched_fds);
+ g_prefetched_fds = key_fd_map;
+ pthread_mutex_unlock(&g_mu);
+}
+#endif
+
int IrtOpenResource(const char* file, int* fd) {
// Remove leading '/' character.
if (file[0] == '/')
++file;
+#if !defined(OS_NACL_SFI)
+ // Fast path for prefetched FDs.
+ pthread_mutex_lock(&g_mu);
+ if (g_prefetched_fds) {
+ std::map<std::string, int>::iterator it = g_prefetched_fds->find(file);
+ if (it != g_prefetched_fds->end()) {
+ *fd = it->second;
+ g_prefetched_fds->erase(it);
+ pthread_mutex_unlock(&g_mu);
+ return 0;
+ }
+ }
+ pthread_mutex_unlock(&g_mu);
+#endif
+
ManifestService* manifest_service = GetManifestService();
if (manifest_service == NULL ||
!manifest_service->OpenResource(file, fd)) {