Commit 284b03c2 authored by jvoung@google.com's avatar jvoung@google.com

Add ability to load pnacl resources from DIR_PNACL_COMPONENT.

Currently hidden behind a flag --enable-pnacl.

This currently reuses the manifest-system of resolving URLs.
Much of that can be simplified later on.

BUG= http://code.google.com/p/nativeclient/issues/detail?id=2365
TEST=

(1) out/Debug/chrome --user-data-dir=/tmp/temp_profile/ --enable-pnacl --component-updater-debug=fast-update

(2) wait a while for it to download pnacl

(3) surf to a pnacl webpage

Review URL: https://chromiumcodereview.appspot.com/10689012

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@151303 0039d316-1c4b-4281-b951-d872f2087c98
parent d430b563
......@@ -821,6 +821,7 @@ void ChromeContentBrowserClient::AppendExtraCommandLineSwitches(
switches::kEnableNaCl,
switches::kEnableNaClIPCProxy,
switches::kEnablePasswordGeneration,
switches::kEnablePnacl,
switches::kEnableWatchdog,
switches::kExperimentalSpellcheckerFeatures,
switches::kMemoryProfiling,
......
......@@ -313,6 +313,11 @@ PP_Bool IsOffTheRecord() {
return PP_FromBool(ChromeRenderProcessObserver::is_incognito_process());
}
PP_Bool IsPnaclEnabled() {
return PP_FromBool(CommandLine::ForCurrentProcess()->HasSwitch(
switches::kEnablePnacl));
}
const PPB_NaCl_Private nacl_interface = {
&LaunchSelLdr,
&StartPpapiProxy,
......@@ -322,7 +327,8 @@ const PPB_NaCl_Private nacl_interface = {
&BrokerDuplicateHandle,
&GetReadonlyPnaclFD,
&CreateTemporaryFile,
&IsOffTheRecord
&IsOffTheRecord,
&IsPnaclEnabled
};
} // namespace
......
......@@ -8,7 +8,7 @@
#include "ppapi/c/private/pp_file_handle.h"
/* PPB_NaCl_Private */
interface PPB_NaCl_Private_0_8 {
interface PPB_NaCl_Private_0_9 {
/* This function launches NaCl's sel_ldr process. On success, the function
* returns true, otherwise it returns false. When it returns true, it will
* write |socket_count| nacl::Handles to imc_handles.
......@@ -49,5 +49,9 @@ interface PPB_NaCl_Private_0_8 {
/* Return true if we are off the record.
*/
PP_Bool IsOffTheRecord([in] PP_Instance instance);
PP_Bool IsOffTheRecord();
/* Return true if PNaCl is turned on.
*/
PP_Bool IsPnaclEnabled();
};
......@@ -11,7 +11,7 @@
#include "ppapi/c/pp_stdint.h"
#include "ppapi/c/private/pp_file_handle.h"
#define PPB_NACL_PRIVATE_INTERFACE "PPB_NaCl(Private);0.8"
#define PPB_NACL_PRIVATE_INTERFACE "PPB_NaCl(Private);0.9"
struct PPB_NaCl_Private {
// This function launches NaCl's sel_ldr process. On success, the function
......@@ -68,7 +68,10 @@ struct PPB_NaCl_Private {
PP_FileHandle (*CreateTemporaryFile)(PP_Instance instance);
// Return true if we are off the record.
PP_Bool (*IsOffTheRecord)();
PP_Bool (*IsOffTheRecord)(void);
// Return true if PNaCl is turned on.
PP_Bool (*IsPnaclEnabled)(void);
};
#endif // PPAPI_C_PRIVATE_PPB_NACL_PRIVATE_H_
......@@ -319,7 +319,7 @@ class Plugin : public pp::InstancePrivate {
return main_service_runtime()->exit_status();
}
const PPB_NaCl_Private* nacl_interface() { return nacl_interface_; }
const PPB_NaCl_Private* nacl_interface() const { return nacl_interface_; }
private:
NACL_DISALLOW_COPY_AND_ASSIGN(Plugin);
......
......@@ -33,12 +33,17 @@ namespace plugin {
//////////////////////////////////////////////////////////////////////
// Pnacl-specific manifest support.
//////////////////////////////////////////////////////////////////////
class ExtensionManifest : public Manifest {
class PnaclManifest : public Manifest {
public:
explicit ExtensionManifest(const pp::URLUtil_Dev* url_util)
PnaclManifest(const pp::URLUtil_Dev* url_util, bool use_extension)
: url_util_(url_util),
manifest_base_url_(PnaclUrls::GetExtensionUrl()) { }
virtual ~ExtensionManifest() { }
manifest_base_url_(PnaclUrls::GetBaseUrl(use_extension)) {
// TODO(jvoung): get rid of use_extension when we no longer rely
// on the chrome webstore extension. Most of this Manifest stuff
// can also be simplified then.
}
virtual ~PnaclManifest() { }
virtual bool GetProgramURL(nacl::string* full_url,
nacl::string* cache_identity,
......@@ -49,7 +54,7 @@ class ExtensionManifest : public Manifest {
UNREFERENCED_PARAMETER(cache_identity);
UNREFERENCED_PARAMETER(error_info);
UNREFERENCED_PARAMETER(pnacl_translate);
PLUGIN_PRINTF(("ExtensionManifest does not contain a program\n"));
PLUGIN_PRINTF(("PnaclManifest does not contain a program\n"));
error_info->SetReport(ERROR_MANIFEST_GET_NEXE_URL,
"pnacl manifest does not contain a program.");
return false;
......@@ -67,7 +72,7 @@ class ExtensionManifest : public Manifest {
virtual bool GetFileKeys(std::set<nacl::string>* keys) const {
// Does not support enumeration.
PLUGIN_PRINTF(("ExtensionManifest does not support key enumeration\n"));
PLUGIN_PRINTF(("PnaclManifest does not support key enumeration\n"));
UNREFERENCED_PARAMETER(keys);
return false;
}
......@@ -95,7 +100,7 @@ class ExtensionManifest : public Manifest {
}
private:
NACL_DISALLOW_COPY_AND_ASSIGN(ExtensionManifest);
NACL_DISALLOW_COPY_AND_ASSIGN(PnaclManifest);
const pp::URLUtil_Dev* url_util_;
nacl::string manifest_base_url_;
......@@ -205,7 +210,7 @@ PnaclCoordinator* PnaclCoordinator::BitcodeToNative(
resource_urls,
resources_cb));
CHECK(coordinator->resources_ != NULL);
coordinator->resources_->StartDownloads();
coordinator->resources_->StartLoad();
// ResourcesDidLoad will be invoked when all resources have been received.
return coordinator;
}
......@@ -238,7 +243,9 @@ PnaclCoordinator::PnaclCoordinator(
plugin_(plugin),
translate_notify_callback_(translate_notify_callback),
file_system_(new pp::FileSystem(plugin, PP_FILESYSTEMTYPE_LOCALTEMPORARY)),
manifest_(new ExtensionManifest(plugin->url_util())),
manifest_(new PnaclManifest(
plugin->url_util(),
plugin::PnaclUrls::UsePnaclExtension(plugin))),
pexe_url_(pexe_url),
cache_identity_(cache_identity),
error_already_reported_(false),
......
......@@ -240,7 +240,6 @@ class PnaclCoordinator: public CallbackSource<FileStreamData> {
// Keep this last in declaration order to ensure the other variables
// haven't been destroyed yet when its destructor runs.
nacl::scoped_ptr<PnaclTranslateThread> translate_thread_;
};
//----------------------------------------------------------------------
......
......@@ -18,9 +18,39 @@ namespace plugin {
const char PnaclUrls::kExtensionOrigin[] =
"chrome-extension://gcodniebolpnpaiggndmcmmfpldlknih/";
const char PnaclUrls::kPnaclComponentID[] =
"pnacl-component://";
const char PnaclUrls::kLlcUrl[] = "llc";
const char PnaclUrls::kLdUrl[] = "ld";
bool PnaclUrls::UsePnaclExtension(const Plugin* plugin) {
// Use the chrome webstore extension for now, if --enable-pnacl is not
// explicitly requested. Eventually we will always behave as if
// --enable-pnacl is used and not use the chrome extension.
// Some UI work, etc. remains before --enable-pnacl is usable:
// http://code.google.com/p/nativeclient/issues/detail?id=2813
return !(plugin->nacl_interface()->IsPnaclEnabled());
}
nacl::string PnaclUrls::GetBaseUrl(bool use_extension) {
if (use_extension) {
return nacl::string(kExtensionOrigin) + GetSandboxISA() + "/";
} else {
return nacl::string(kPnaclComponentID) + GetSandboxISA() + "/";
}
}
bool PnaclUrls::IsPnaclComponent(const nacl::string& full_url) {
return full_url.find(kPnaclComponentID, 0) == 0;
}
nacl::string PnaclUrls::StripPnaclComponentPrefix(
const nacl::string& full_url) {
return full_url.substr(nacl::string(kPnaclComponentID).length());
}
//////////////////////////////////////////////////////////////////////
PnaclResources::~PnaclResources() {
for (std::map<nacl::string, nacl::DescWrapper*>::iterator
i = resource_wrappers_.begin(), e = resource_wrappers_.end();
......@@ -31,35 +61,100 @@ PnaclResources::~PnaclResources() {
resource_wrappers_.clear();
}
void PnaclResources::StartDownloads() {
PLUGIN_PRINTF(("PnaclResources::StartDownloads\n"));
// Create a counter (barrier) callback to track when all of the resources
// are loaded.
uint32_t resource_count = static_cast<uint32_t>(resource_urls_.size());
delayed_callback_.reset(
new DelayedCallback(all_loaded_callback_, resource_count));
// static
int32_t PnaclResources::GetPnaclFD(Plugin* plugin, const char* filename) {
PP_FileHandle file_handle =
plugin->nacl_interface()->GetReadonlyPnaclFd(filename);
if (file_handle == PP_kInvalidFileHandle)
return -1;
#if NACL_WINDOWS
//////// Now try the posix view.
int32_t posix_desc = _open_osfhandle(reinterpret_cast<intptr_t>(file_handle),
_O_RDONLY | _O_BINARY);
if (posix_desc == -1) {
PLUGIN_PRINTF((
"PnaclResources::GetPnaclFD failed to convert HANDLE to posix\n"));
// Close the Windows HANDLE if it can't be converted.
CloseHandle(file_handle);
}
return posix_desc;
#else
return file_handle;
#endif
}
nacl::DescWrapper* PnaclResources::WrapperForUrl(const nacl::string& url) {
CHECK(resource_wrappers_.find(url) != resource_wrappers_.end());
return resource_wrappers_[url];
}
void PnaclResources::StartLoad() {
PLUGIN_PRINTF(("PnaclResources::StartLoad\n"));
// Schedule the downloads.
CHECK(resource_urls_.size() > 0);
for (size_t i = 0; i < resource_urls_.size(); ++i) {
nacl::string full_url;
ErrorInfo error_info;
if (!manifest_->ResolveURL(resource_urls_[i], &full_url, &error_info)) {
coordinator_->ReportNonPpapiError(nacl::string("failed to resolve ") +
resource_urls_[i] + ": " +
error_info.message() + ".");
break;
if (PnaclUrls::UsePnaclExtension(plugin_)) {
PLUGIN_PRINTF(("PnaclResources::StartLoad -- PNaCl chrome extension.\n"));
// Do a URL fetch.
// Create a counter (barrier) callback to track when all of the resources
// are loaded.
uint32_t resource_count = static_cast<uint32_t>(resource_urls_.size());
delayed_callback_.reset(
new DelayedCallback(all_loaded_callback_, resource_count));
// Schedule the downloads.
for (size_t i = 0; i < resource_urls_.size(); ++i) {
nacl::string full_url;
ErrorInfo error_info;
if (!manifest_->ResolveURL(resource_urls_[i], &full_url, &error_info)) {
coordinator_->ReportNonPpapiError(nacl::string("failed to resolve ") +
resource_urls_[i] + ": " +
error_info.message() + ".");
break;
}
pp::CompletionCallback ready_callback =
callback_factory_.NewCallback(
&PnaclResources::ResourceReady,
resource_urls_[i],
full_url);
if (!plugin_->StreamAsFile(full_url,
ready_callback.pp_completion_callback())) {
coordinator_->ReportNonPpapiError(nacl::string("failed to download ") +
resource_urls_[i] + ".");
break;
}
}
pp::CompletionCallback ready_callback =
callback_factory_.NewCallback(&PnaclResources::ResourceReady,
resource_urls_[i],
full_url);
if (!plugin_->StreamAsFile(full_url,
ready_callback.pp_completion_callback())) {
coordinator_->ReportNonPpapiError(nacl::string("failed to download ") +
resource_urls_[i] + ".");
break;
} else {
PLUGIN_PRINTF(("PnaclResources::StartLoad -- local install of PNaCl.\n"));
// Do a blocking load of each of the resources.
int32_t result = PP_OK;
for (size_t i = 0; i < resource_urls_.size(); ++i) {
const nacl::string& url = resource_urls_[i];
nacl::string full_url;
ErrorInfo error_info;
if (!manifest_->ResolveURL(resource_urls_[i], &full_url, &error_info)) {
coordinator_->ReportNonPpapiError(nacl::string("failed to resolve ") +
url + ": " +
error_info.message() + ".");
break;
}
full_url = PnaclUrls::StripPnaclComponentPrefix(full_url);
int32_t fd = PnaclResources::GetPnaclFD(plugin_, full_url.c_str());
if (fd < 0) {
coordinator_->ReportNonPpapiError(
nacl::string("PnaclLocalResources::StartLoad failed for: ") +
full_url);
result = PP_ERROR_FILENOTFOUND;
break;
} else {
resource_wrappers_[url] =
plugin_->wrapper_factory()->MakeFileDesc(fd, O_RDONLY);
}
}
// We're done! Queue the callback.
pp::Core* core = pp::Module::Get()->core();
core->CallOnMainThread(0, all_loaded_callback_, result);
}
}
......
......@@ -15,6 +15,8 @@
#include "native_client/src/trusted/plugin/delayed_callback.h"
#include "native_client/src/trusted/plugin/nexe_arch.h"
#include "native_client/src/trusted/plugin/plugin_error.h"
#include "ppapi/c/private/pp_file_handle.h"
#include "ppapi/utility/completion_callback_factory.h"
namespace plugin {
......@@ -23,21 +25,25 @@ class Manifest;
class Plugin;
class PnaclCoordinator;
// Constants for loading LLC and LD.
class PnaclUrls {
public:
static nacl::string GetExtensionUrl() {
return nacl::string(kExtensionOrigin) + GetSandboxISA() + "/";
}
static bool UsePnaclExtension(const Plugin* plugin);
static nacl::string GetBaseUrl(bool use_extension);
static bool IsPnaclComponent(const nacl::string& full_url);
static nacl::string StripPnaclComponentPrefix(const nacl::string& full_url);
static const nacl::string GetLlcUrl() { return nacl::string(kLlcUrl); }
static const nacl::string GetLdUrl() { return nacl::string(kLdUrl); }
private:
static const char kExtensionOrigin[];
static const char kPnaclComponentID[];
static const char kLlcUrl[];
static const char kLdUrl[];
};
// Loads a list of remote resources, providing a way to get file descriptors for
// thse resources. All URLs in relative to resource_base_url_.
// Loads a list of resources, providing a way to get file descriptors for
// these resources. URLs for resources are resolved by the manifest
// and may either point to filesystem resources or chrome extension resources.
class PnaclResources {
public:
PnaclResources(Plugin* plugin,
......@@ -52,16 +58,14 @@ class PnaclResources {
all_loaded_callback_(all_loaded_callback) {
callback_factory_.Initialize(this);
}
virtual ~PnaclResources();
// Start fetching the URLs. After construction, this is the first step.
void StartDownloads();
// Get the wrapper for the downloaded resource.
// Only valid after all_loaded_callback_ has been run.
nacl::DescWrapper* WrapperForUrl(const nacl::string& url) {
return resource_wrappers_[url];
}
// Start loading the resources. After construction, this is the first step.
virtual void StartLoad();
// Get file descs by name. Only valid after all_loaded_callback_ has been run.
nacl::DescWrapper* WrapperForUrl(const nacl::string& url);
static int32_t GetPnaclFD(Plugin* plugin, const char* filename);
private:
NACL_DISALLOW_COPY_AND_ASSIGN(PnaclResources);
......
......@@ -44,6 +44,7 @@
#include "native_client/src/trusted/plugin/plugin.h"
#include "native_client/src/trusted/plugin/plugin_error.h"
#include "native_client/src/trusted/plugin/pnacl_coordinator.h"
#include "native_client/src/trusted/plugin/pnacl_resources.h"
#include "native_client/src/trusted/plugin/sel_ldr_launcher_chrome.h"
#include "native_client/src/trusted/plugin/srpc_client.h"
#include "native_client/src/trusted/plugin/utility.h"
......@@ -244,6 +245,12 @@ bool PluginReverseInterface::OpenManifestEntry(nacl::string url_key,
return true;
}
// Transfer point from OpenManifestEntry() which runs on the main thread
// (Some PPAPI actions -- like StreamAsFile -- can only run on the main thread).
// OpenManifestEntry() is waiting on a condvar for this continuation to
// complete. We Broadcast and awaken OpenManifestEntry() whenever we are done
// either here, or in a later MainThreadContinuation step, if there are
// multiple steps.
void PluginReverseInterface::OpenManifestEntry_MainThreadContinuation(
OpenManifestEntryResource* p,
int32_t err) {
......@@ -280,21 +287,45 @@ void PluginReverseInterface::OpenManifestEntry_MainThreadContinuation(
this,
&PluginReverseInterface::StreamAsFile_MainThreadContinuation,
open_cont);
if (!plugin_->StreamAsFile(mapped_url,
stream_cc.pp_completion_callback())) {
//
if (!PnaclUrls::IsPnaclComponent(mapped_url)) {
if (!plugin_->StreamAsFile(mapped_url,
stream_cc.pp_completion_callback())) {
NaClLog(4,
"OpenManifestEntry_MainThreadContinuation: "
"StreamAsFile failed\n");
nacl::MutexLocker take(&mu_);
*p->op_complete_ptr = true; // done...
*p->out_desc = -1; // but failed.
p->error_info->SetReport(ERROR_MANIFEST_OPEN,
"ServiceRuntime: StreamAsFile failed");
NaClXCondVarBroadcast(&cv_);
return;
}
NaClLog(4,
"OpenManifestEntry_MainThreadContinuation: "
"StreamAsFile failed\n");
"OpenManifestEntry_MainThreadContinuation: StreamAsFile okay\n");
} else {
int32_t fd = PnaclResources::GetPnaclFD(
plugin_,
PnaclUrls::StripPnaclComponentPrefix(mapped_url).c_str());
if (fd < 0) {
// We should check earlier if the pnacl component wasn't installed
// yet. At this point, we can't do much anymore, so just continue
// with an invalid fd.
NaClLog(4,
"OpenManifestEntry_MainThreadContinuation: "
"GetReadonlyPnaclFd failed\n");
// TODO(jvoung): Separate the error codes?
p->error_info->SetReport(ERROR_MANIFEST_OPEN,
"ServiceRuntime: GetPnaclFd failed");
}
nacl::MutexLocker take(&mu_);
*p->op_complete_ptr = true; // done...
*p->out_desc = -1; // but failed.
p->error_info->SetReport(ERROR_MANIFEST_OPEN,
"ServiceRuntime: StreamAsFile failed");
*p->op_complete_ptr = true; // done!
*p->out_desc = fd;
NaClXCondVarBroadcast(&cv_);
return;
NaClLog(4,
"OpenManifestEntry_MainThreadContinuation: GetPnaclFd okay\n");
}
NaClLog(4,
"OpenManifestEntry_MainThreadContinuation: StreamAsFile okay\n");
} else {
NaClLog(4,
"OpenManifestEntry_MainThreadContinuation: "
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment