Chromium Code Reviews| Index: components/nacl/renderer/ppb_nacl_private_impl.cc |
| diff --git a/components/nacl/renderer/ppb_nacl_private_impl.cc b/components/nacl/renderer/ppb_nacl_private_impl.cc |
| index 3c84afe5d1ee4a16187fef0b715342f5b239acf4..3b0f6ce285afdabb041e75291014174c1590036f 100644 |
| --- a/components/nacl/renderer/ppb_nacl_private_impl.cc |
| +++ b/components/nacl/renderer/ppb_nacl_private_impl.cc |
| @@ -16,6 +16,7 @@ |
| #include "base/files/file.h" |
| #include "base/lazy_instance.h" |
| #include "base/logging.h" |
| +#include "base/macros.h" |
| #include "base/rand_util.h" |
| #include "base/strings/string_split.h" |
| #include "base/strings/string_util.h" |
| @@ -41,6 +42,7 @@ |
| #include "content/public/renderer/render_thread.h" |
| #include "content/public/renderer/render_view.h" |
| #include "content/public/renderer/renderer_ppapi_host.h" |
| +#include "ipc/ipc_message_attachment_set.h" |
| #include "native_client/src/public/imc_types.h" |
| #include "net/base/data_url.h" |
| #include "net/base/net_errors.h" |
| @@ -73,6 +75,20 @@ const char* const kPortableArch = "portable"; |
| // The base URL for resources used by the PNaCl translator processes. |
| const char* kPNaClTranslatorBaseUrl = "chrome://pnacl-translator/"; |
| +// The maximum number of resource files DownloadNexe() can open. |
| +const size_t kMaxPreOpenResourceFiles = 2; |
|
Mark Seaborn
2015/02/09 04:48:34
Why so low? I thought your aim was to pass more t
Yusuke Sato
2015/02/11 05:54:21
This is currently 2 because kMaxDescriptorsPerMess
Mark Seaborn
2015/02/12 03:57:33
OK, so the test is still covering the fast path.
Yusuke Sato
2015/02/13 23:01:16
Done.
|
| + |
| +#if defined(OS_POSIX) |
| +// On POSIX platforms, the maximum number of files a process can pass to |
| +// another is limited to kMaxDescriptorsPerMessage. Since the browser process |
| +// may use up to 5 descriptors for passing non-resource files when creating |
| +// the NaCl plugin process, kMaxPreOpenResourceFiles must be smaller than or |
| +// equal to (IPC::MessageAttachmentSet::kMaxDescriptorsPerMessage - 5). |
| +COMPILE_ASSERT(kMaxPreOpenResourceFiles <= |
| + IPC::MessageAttachmentSet::kMaxDescriptorsPerMessage - 5, |
| + k_max_pre_open_resource_files_too_large); |
| +#endif |
| + |
| base::LazyInstance<scoped_refptr<PnaclTranslationResourceHost> > |
| g_pnacl_resource_host = LAZY_INSTANCE_INITIALIZER; |
| @@ -108,6 +124,7 @@ class NaClPluginInstance { |
| NexeLoadManager nexe_load_manager; |
| scoped_ptr<JsonManifest> json_manifest; |
| scoped_ptr<InstanceInfo> instance_info; |
| + std::vector<NaClLaunchParams::ResourceFileInfo> resource_files_info; |
|
Mark Seaborn
2015/02/09 04:48:34
If I read this right, NaClLaunchParams::ResourceFi
Yusuke Sato
2015/02/11 05:54:21
You're right. The IPC::PlatformFileForTransit hand
|
| // When translation is complete, this records the size of the pexe in |
| // bytes so that it can be reported in a later load event. |
| @@ -401,14 +418,20 @@ void LaunchSelLdr(PP_Instance instance, |
| IPC::PlatformFileForTransit nexe_for_transit = |
| IPC::InvalidPlatformFileForTransit(); |
| + |
| + NaClPluginInstance* nacl_plugin_instance = GetNaClPluginInstance(instance); |
| #if defined(OS_POSIX) |
| if (nexe_file_info->handle != PP_kInvalidFileHandle) |
| nexe_for_transit = base::FileDescriptor(nexe_file_info->handle, true); |
| + const std::vector<NaClLaunchParams::ResourceFileInfo>& resource_files_info = |
| + nacl_plugin_instance->resource_files_info; |
|
Mark Seaborn
2015/02/09 04:48:34
Shouldn't nacl_plugin_instance->resource_files_inf
Yusuke Sato
2015/02/11 05:54:21
Done.
|
| #elif defined(OS_WIN) |
| // Duplicate the handle on the browser side instead of the renderer. |
| // This is because BrokerGetFileForProcess isn't part of content/public, and |
| // it's simpler to do the duplication in the browser anyway. |
| nexe_for_transit = nexe_file_info->handle; |
| + // TODO(yusukes): Support pre-opening resource files. |
|
Mark Seaborn
2015/02/09 04:48:34
Add "on Windows"?
Yusuke Sato
2015/02/11 05:54:21
Done.
|
| + std::vector<NaClLaunchParams::ResourceFileInfo> resource_files_info; // empty |
| #else |
| #error Unsupported target platform. |
| #endif |
| @@ -418,6 +441,7 @@ void LaunchSelLdr(PP_Instance instance, |
| nexe_for_transit, |
| nexe_file_info->token_lo, |
| nexe_file_info->token_hi, |
| + resource_files_info, |
| routing_id, |
| perm_bits, |
| PP_ToBool(uses_nonsfi_mode), |
| @@ -451,10 +475,8 @@ void LaunchSelLdr(PP_Instance instance, |
| instance_info.plugin_child_id = launch_result.plugin_child_id; |
| // Don't save instance_info if channel handle is invalid. |
| - if (IsValidChannelHandle(instance_info.channel_handle)) { |
| - NaClPluginInstance* nacl_plugin_instance = GetNaClPluginInstance(instance); |
| + if (IsValidChannelHandle(instance_info.channel_handle)) |
| nacl_plugin_instance->instance_info.reset(new InstanceInfo(instance_info)); |
| - } |
| *(static_cast<NaClHandle*>(imc_handle)) = ToNativeHandle(result_socket); |
| @@ -583,18 +605,19 @@ PP_FileHandle GetReadonlyPnaclFd(const char* url, |
| uint64_t* nonce_lo, |
| uint64_t* nonce_hi) { |
| std::string filename = PnaclComponentURLToFilename(url); |
| - IPC::PlatformFileForTransit out_fd = IPC::InvalidPlatformFileForTransit(); |
| IPC::Sender* sender = content::RenderThread::Get(); |
| + NaClFileInfo file_info; |
| DCHECK(sender); |
| if (!sender->Send(new NaClHostMsg_GetReadonlyPnaclFD( |
| - std::string(filename), is_executable, |
| - &out_fd, nonce_lo, nonce_hi))) { |
| + std::string(filename), is_executable, &file_info))) { |
| return PP_kInvalidFileHandle; |
| } |
| - if (out_fd == IPC::InvalidPlatformFileForTransit()) { |
| + if (file_info.file == IPC::InvalidPlatformFileForTransit()) { |
| return PP_kInvalidFileHandle; |
| } |
| - return IPC::PlatformFileForTransitToPlatformFile(out_fd); |
| + *nonce_lo = file_info.file_token_lo; |
| + *nonce_hi = file_info.file_token_hi; |
| + return IPC::PlatformFileForTransitToPlatformFile(file_info.file); |
| } |
| void GetReadExecPnaclFd(const char* url, |
| @@ -707,14 +730,13 @@ void ReportTranslationFinished(PP_Instance instance, |
| } |
| } |
| -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; |
| +bool OpenNaClResources( |
| + PP_Instance instance, |
| + const std::vector<std::string>& resource_file_urls, |
| + std::vector<NaClFileInfo>* out_resource_file_handles) { |
| + DCHECK(out_resource_file_handles); |
| + if (resource_file_urls.empty()) |
| + return false; |
| NexeLoadManager* load_manager = GetNexeLoadManager(instance); |
| DCHECK(load_manager); |
| @@ -724,36 +746,45 @@ PP_FileHandle OpenNaClExecutable(PP_Instance instance, |
| content::PepperPluginInstance* plugin_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. |
| + return false; |
| blink::WebSecurityOrigin security_origin = |
| plugin_instance->GetContainer()->element().document().securityOrigin(); |
| - if (!security_origin.canRequest(gurl)) |
| - return PP_kInvalidFileHandle; |
| - |
| - IPC::PlatformFileForTransit out_fd = IPC::InvalidPlatformFileForTransit(); |
| IPC::Sender* sender = content::RenderThread::Get(); |
| DCHECK(sender); |
| - *nonce_lo = 0; |
| - *nonce_hi = 0; |
| - base::FilePath file_path; |
| - if (!sender->Send( |
| - new NaClHostMsg_OpenNaClExecutable(GetRoutingID(instance), |
| - GURL(file_url), |
| - !load_manager->nonsfi(), |
| - &out_fd, |
| - nonce_lo, |
| - nonce_hi))) { |
| - return PP_kInvalidFileHandle; |
| + |
| + std::vector<GURL> resource_gurls; |
| + for (size_t i = 0; i < resource_file_urls.size(); ++i) { |
| + resource_gurls.push_back(GURL(resource_file_urls[i])); |
| } |
| - if (out_fd == IPC::InvalidPlatformFileForTransit()) |
| - return PP_kInvalidFileHandle; |
| + for (size_t i = 0; i < resource_gurls.size(); ++i) { |
| + const GURL& gurl = resource_gurls[i]; |
| + // Fast path only works for installed file URLs. |
| + if (!gurl.SchemeIs("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 (!security_origin.canRequest(gurl)) |
| + return false; |
| + } |
| + |
| + if (!sender->Send(new NaClHostMsg_OpenNaClResources( |
| + GetRoutingID(instance), |
| + resource_gurls, |
| + !load_manager->nonsfi(), |
| + out_resource_file_handles))) { |
| + return false; |
| + } |
| - return IPC::PlatformFileForTransitToPlatformFile(out_fd); |
| + if (out_resource_file_handles->empty() || |
| + (out_resource_file_handles->at(0).file == |
| + IPC::InvalidPlatformFileForTransit())) { |
| + DLOG(ERROR) << "Could not open the main nexe: " << resource_gurls[0]; |
| + return false; |
| + } |
| + return true; |
| } |
| void DispatchEvent(PP_Instance instance, |
| @@ -1211,6 +1242,7 @@ void DownloadNexeCompletion(const DownloadNexeRequest& request, |
| void DownloadNexe(PP_Instance instance, |
| const char* url, |
| + PP_Bool download_resource_files, |
| PP_NaClFileInfo* out_file_info, |
| PP_CompletionCallback callback) { |
| CHECK(url); |
| @@ -1221,16 +1253,40 @@ void DownloadNexe(PP_Instance instance, |
| request.callback = callback; |
| request.start_time = base::Time::Now(); |
| + std::vector<std::string> file_urls; |
| + file_urls.push_back(url); // the main nexe must be the first element. |
| + |
| + std::vector< |
| + std::pair<std::string /*url*/, std::string /*key*/> > resource_files; |
| + if (download_resource_files) { |
| + JsonManifest* manifest = GetJsonManifest(instance); |
| + if (manifest) |
| + manifest->GetFiles(&resource_files); |
| + if (resource_files.size() > kMaxPreOpenResourceFiles) |
| + resource_files.resize(kMaxPreOpenResourceFiles); |
| + for (size_t i = 0; i < resource_files.size(); ++i) { |
| + file_urls.push_back(resource_files[i].first); |
| + } |
| + } |
| + |
| // Try the fast path for retrieving the file first. |
| - PP_FileHandle handle = OpenNaClExecutable(instance, |
| - url, |
| - &out_file_info->token_lo, |
| - &out_file_info->token_hi); |
| - if (handle != PP_kInvalidFileHandle) { |
| + std::vector<NaClFileInfo> file_handles; |
| + if (OpenNaClResources(instance, file_urls, &file_handles)) { |
| + DCHECK(!file_handles.empty()); |
| + out_file_info->handle = |
| + IPC::PlatformFileForTransitToPlatformFile(file_handles[0].file); |
| + out_file_info->token_lo = file_handles[0].file_token_lo; |
| + out_file_info->token_hi = file_handles[0].file_token_hi; |
| + NaClPluginInstance* nacl_plugin_instance = GetNaClPluginInstance(instance); |
| + for (size_t i = 1; i < file_handles.size(); ++i) { |
| + std::string key = resource_files[i - 1].second; |
| + nacl_plugin_instance->resource_files_info.push_back( |
| + NaClLaunchParams::ResourceFileInfo(file_handles[i], key)); |
| + } |
| DownloadNexeCompletion(request, |
| out_file_info, |
| FileDownloader::SUCCESS, |
| - base::File(handle), |
| + base::File(out_file_info->handle), |
| 200); |
| return; |
| } |
| @@ -1240,6 +1296,7 @@ void DownloadNexe(PP_Instance instance, |
| base::File target_file(CreateTemporaryFile(instance)); |
| GURL gurl(url); |
| + // On the slow path, do not retry to pre-open the resource files. |
| content::PepperPluginInstance* plugin_instance = |
| content::PepperPluginInstance::Get(instance); |
| if (!plugin_instance) { |
| @@ -1375,17 +1432,15 @@ void DownloadFile(PP_Instance instance, |
| } |
| // Try the fast path for retrieving the file first. |
| - uint64_t file_token_lo = 0; |
| - uint64_t file_token_hi = 0; |
| - PP_FileHandle file_handle = OpenNaClExecutable(instance, |
| - url.c_str(), |
| - &file_token_lo, |
| - &file_token_hi); |
| - if (file_handle != PP_kInvalidFileHandle) { |
| + std::vector<std::string> file_urls; |
| + file_urls.push_back(url); |
| + std::vector<NaClFileInfo> out_handles; |
| + if (OpenNaClResources(instance, file_urls, &out_handles)) { |
|
Mark Seaborn
2015/02/09 04:48:35
I think there's a potential performance regression
Yusuke Sato
2015/02/11 05:54:21
I wasn't aware that HTTP(S) URL was allowed in "fi
|
| PP_NaClFileInfo file_info; |
| - file_info.handle = file_handle; |
| - file_info.token_lo = file_token_lo; |
| - file_info.token_hi = file_token_hi; |
| + file_info.handle = |
| + IPC::PlatformFileForTransitToPlatformFile(out_handles[0].file); |
| + file_info.token_lo = out_handles[0].file_token_lo; |
| + file_info.token_hi = out_handles[0].file_token_hi; |
| base::MessageLoop::current()->PostTask( |
| FROM_HERE, |
| base::Bind(callback, static_cast<int32_t>(PP_OK), file_info)); |